C#优化递归树形

html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="../../Scripts/bootstrap/js/bootstrap/css/bootstrap.css" rel="stylesheet" />
    <link href="../../Scripts/bootstrap/js/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet" />
    <link href="../../Scripts/bootstrap/js/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
    <link href="../../Scripts/bootstrap/js/jquery.treegrid.min.css" rel="stylesheet" />
    <script src="../../Scripts/bootstrap/js/jQuery1.11.3.min.js"></script>
    <script src="../../Scripts/bootstrap/js/bootstrap/js/bootstrap.min.js"></script>
    <script src="../../Scripts/bootstrap/js/bootstrap-table/bootstrap-table.min.js"></script>
    <script src="../../Scripts/bootstrap/js/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
    <script src="../../Scripts/bootstrap/js/jquery.treegrid.js"></script>
    <script src="../../Scripts/bootstrap/js/bootstrap-table/jquery.treegrid.ajax.js"></script>
    <style>
        tr.checked-item {
            background-color: #d4e1f5 !important;
        }
    </style>
</head>
<body>
    <table id="table"></table>
    <script>
        $(function () {
            var name = parent.$("#FullBodyContent_MainName").val();
            var $table = $("#table");
            $table.myAjaxTreeTable({
                url: 'treegrid.ashx?func=tree',
                ajaxParams: { name: name,type:"sbxj" },
                rootidValue: "",
                striped: true,
                expandColumn: 0,
                columns: [
                    {
                        field: 'name',
                        title: '名称',
                    }, {
                        field: 'step',
                        title: '步骤'
                    }, {
                        field: 'required',
                        title: '关键点'
                    },
                ],
            });
        })

    </script>
</body>
</html>
View Code

ashx:

using Ext.Net;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using XLT.QC.Domain;
using XLT.QC.Entity;

namespace XLT.QC.Web.Admin.RepairAdmin
{
    /// <summary>
    /// treegrid 的摘要说明
    /// </summary>
    public class treegrid : IHttpHandler
    {
        TestingMachineProcessDomain _testDomain = new TestingMachineProcessDomain();
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            string func = context.Request["func"];
            switch (func)
            {
                case "tree":
                    getTreeGridData(context);
                    break;
                case "childtree":
                    getChildNodeData(context);
                    break;
                default:
                    break;
            }
        }

        public void getTreeGridData(HttpContext context)
        {
            string type = context.Request["type"];
            string name = context.Request["name"];
            DataSet ds = _testDomain.getNodeData(name,type);
            List<MachineProcess> list = new List<MachineProcess>();
            for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
            {
                MachineProcess entity = new MachineProcess();
                entity.name = ds.Tables[0].Rows[i]["Name"].ToString();
                entity.id = ds.Tables[0].Rows[i]["Id"].ToString();
                entity.pid = ds.Tables[0].Rows[i]["Pid"].ToString();
                if (!string.IsNullOrWhiteSpace(ds.Tables[0].Rows[i]["Step"].ToString()))
                {
                    entity.step = Convert.ToInt32(ds.Tables[0].Rows[i]["Step"]);
                }
                if (!string.IsNullOrWhiteSpace(ds.Tables[0].Rows[i]["Level"].ToString()))
                {
                    entity.level = Convert.ToInt32(ds.Tables[0].Rows[i]["Level"]);
                }
                entity.required = ds.Tables[0].Rows[i]["Required"].ToString();
                entity.isLeaf= true;
                list.Add(entity);
            }
            string jsonStr = JSON.Serialize(list);
            context.Response.Write(jsonStr);
        }

        public void getChildNodeData(HttpContext context) 
        {
            string pid = context.Request["pid"];
            string type = context.Request["type"];
            string table = "TestingMachineProcess";
            if (type=="sbxj")
            {
                table = "ArtificialProcess";
            }
            string sql = "select Id,Pid,Name,Step,Level,QualityStandard,Required from " + table + " where Pid='" + pid + "' and (IsValid is null or IsValid=1) order by Step asc";

            DataSet ds = ISS.DataAccess.DbHelper.ExecuteDataSetBySql(sql);
            List<MachineProcess> list = new List<MachineProcess>();
            for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
            {
                MachineProcess entity = new MachineProcess();
                entity.name = ds.Tables[0].Rows[i]["Name"].ToString();
                entity.id = ds.Tables[0].Rows[i]["Id"].ToString();
                entity.pid = ds.Tables[0].Rows[i]["Pid"].ToString();
                if (!string.IsNullOrWhiteSpace(ds.Tables[0].Rows[i]["Step"].ToString()))
                {
                    entity.step = Convert.ToInt32(ds.Tables[0].Rows[i]["Step"]);
                }
                if (!string.IsNullOrWhiteSpace(ds.Tables[0].Rows[i]["Level"].ToString()))
                {
                    entity.level = Convert.ToInt32(ds.Tables[0].Rows[i]["Level"]);
                }
                entity.required = ds.Tables[0].Rows[i]["Required"].ToString();

                IDataReader dr = ISS.DataAccess.DbHelper.ExecuteReaderBySql("select COUNT(1) num from TestingMachineProcess where Pid='" + entity.id + "' ");
                if (dr.Read())
                {
                    if (Convert.ToInt32(dr["num"].ToString()) > 0)
                    {
                        entity.isLeaf = true;

                    }
                    else
                    {
                        entity.isLeaf = false;
                    }
                }
                
                dr.Close();
                dr.Dispose();
                list.Add(entity);
            }
            
            string jsonStr = JSON.Serialize(list);
            context.Response.Write(jsonStr);
        }
        public class MachineProcess 
        {
            public string id { get; set; }

            /// <summary>
            /// 父节点
            /// </summary>
            public string pid { get; set; }

            /// <summary>
            /// 名称
            /// </summary>
            public string name { get; set; }

            /// <summary>
            /// 步骤
            /// </summary>
            public int step { get; set; }

            /// <summary>
            /// 级别
            /// </summary>
            public int level { get; set; }

            /// <summary>
            /// 质量标准说明
            /// </summary>
            //public string QualityStandard { get; set; }

            /// <summary>
            /// 
            /// </summary>
            public bool isLeaf { get; set; }

            /// <summary>
            /// 关键点
            /// </summary>
            public string required { get; set; }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

js:

(function ($) {
    "use strict";

    $.fn.myAjaxTreeTable = function (options, param) {
        // 如果是调用方法
        if (typeof options == 'string') {
            return $.fn.myAjaxTreeTable.methods[options](this, param);
        }

        // 如果是初始化组件
        options = $.extend({}, $.fn.myAjaxTreeTable.defaults, options || {});
        // 是否有radio或checkbox
        var hasSelectItem = false;
        var target = $(this);
        // 在外层包装一下div,样式用的bootstrap-table的
        var _main_div = $("<div class='fixed-table-container'></div>");
        target.before(_main_div);
        _main_div.append(target);
        target.addClass("table table-hover treegrid-table table-bordered");
        if (options.striped) {
            target.addClass('table-striped');
        }
        // 工具条在外层包装一下div,样式用的bootstrap-table的
        if (options.toolbar) {
            var _tool_div = $("<div class='fixed-table-toolbar' style='display:none;'></div>");
            var _tool_left_div = $("<div class='bs-bars pull-left'></div>");
            _tool_left_div.append($(options.toolbar));
            _tool_div.append(_tool_left_div);
            _main_div.before(_tool_div);
        }
        // 得到根节点
        target.getRootNodes = function (data) {

            // 指定Root节点值
            var _root = options.rootidValue ? options.rootidValue : "";
            var result = [];
            $.each(data, function (index, item) {
                // 这里兼容几种常见Root节点写法
                // 默认的几种判断
                var _defaultRootFlag = item[options.pid] == '0'
                    || item[options.pid] == 0
                    || item[options.pid] == null
                    || item[options.pid] == '';
                if (!item[options.pid] || (_root ? (item[options.pid] == options.rootidValue) : _defaultRootFlag)) {
                    result.push(item);
                }
                // 添加一个默认属性,用来判断当前节点有没有被显示
                item.isShow = false;
            });
            return result;
        };
        var j = 0;
        // 递归获取子节点并且设置子节点
        target.getChildNodes = function (data, parentNode, parentIndex, tbody) {
            $.each(data, function (i, item) {
                if (item[options.pid] == parentNode[options.id]) {
                    var tr = $('<tr></tr>');
                    var nowParentIndex = (parentIndex + (j++) + 1);
                    tr.addClass('treegrid-' + nowParentIndex);
                    tr.addClass('treegrid-parent-' + parentIndex);
                    tr.addClass('unknow');
                    tr.attr("isLeaf", item.isLeaf);
                    tr.attr("level", item.level);
                    target.renderRow(tr, item);
                    item.isShow = true;
                    tbody.append(tr);
                    target.getChildNodes(data, item, nowParentIndex, tbody)
                }
            });
        };

        target.renderChildRows = function (data, parentNode, parentIndex, tbody) {
            var html = "";
            var parentNum = $(tbody).attr('class').split(" ")[2];
            $.each(data, function (i, item) {
                var tr = $('<tr></tr>');
                var nowParentIndex = parentIndex;
                tr.addClass('treegrid-' + nowParentIndex + i);
                tr.addClass('treegrid-parent-' + parentIndex);
                tr.addClass('unknow');
                tr.attr("isLeaf", item.isLeaf);
                tr.attr("level", item.level);
                target.renderRow(tr, item);
                item.isShow = true;
                html += tr.get(0).outerHTML;
            });
            tbody.after(html);
        };
        // 行添加内容
        target.renderRow = function (tr, item) {
            $.each(options.columns, function (index, column) {
                // 判断有没有选择列
                if (index == 0 && column.field == 'selectItem') {
                    hasSelectItem = true;
                    var td = $('<td style="text-align:center;36px"></td>');
                    if (column.radio) {
                        var _ipt = $('<input name="select_item" type="radio" value="' + item[options.id] + '"></input>');
                        td.append(_ipt);
                    }
                    if (column.checkbox) {
                        var _ipt = $('<input name="select_item" type="checkbox" value="' + item[options.id] + '"></input>');
                        td.append(_ipt);
                    }
                    tr.append(td);
                } else {
                    var html = "<td mainid='" + item[options.id] + "' style='text-align:left;'>";
                    var level = parseInt(item.level);
                    if (index == 0) {
                        if (item.pid != "") {
                            for (var i = 0; i < level; i++) {
                                html += "<span class='treegrid-indent'></span>";
                            }
                        }
                        html += "<span class='treegrid-expander'></span>" + item[column.field] + "</td>";
                    }
                    else {
                        html += item[column.field] + "</td>";
                    }

                    // 增加formatter渲染
                    if (column.formatter) {
                        td.html(column.formatter.call(this, item, index));
                    }
                    tr.append($(html));
                }
            });
        }
        // 加载数据
        target.load = function (parms) {
            // 加载数据前先清空
            target.html("");
            // 构造表头
            var thr = $('<tr></tr>');
            $.each(options.columns, function (i, item) {
                var th = null;
                // 判断有没有选择列
                if (i == 0 && item.field == 'selectItem') {
                    hasSelectItem = true;
                    th = $('<th style="text-align:' + item.valign + ';36px"></th>');
                } else {
                    th = $('<th style="text-align:' + item.valign + ';padding:10px;' + ((item.width) ? ('' + item.width) : '') + '"></th>');
                }
                th.text(item.title);
                thr.append(th);
            });
            var thead = $('<thead class="treegrid-thead"></thead>');
            thead.append(thr);
            target.append(thead);
            // 构造表体
            var tbody = $('<tbody class="treegrid-tbody"></tbody>');
            target.append(tbody);
            // 添加加载loading
            var _loading = '<tr><td colspan="' + options.columns.length + '"><div style="display: block;text-align: center;">正在努力地加载数据中,请稍候……</div></td></tr>'
            tbody.html(_loading);
            // 默认高度
            if (options.height) {
                tbody.css("height", options.height);
            }
            $.ajax({
                type: options.type,
                url: options.url,
                data: parms ? parms : options.ajaxParams,
                dataType: "JSON",
                success: function (data, textStatus, jqXHR) {
                    // 加载完数据先清空
                    tbody.html("");
                    if (!data || data.length <= 0) {
                        var _empty = '<tr><td colspan="' + options.columns.length + '"><div style="display: block;text-align: center;">没有记录</div></td></tr>'
                        tbody.html(_empty);
                        return;
                    }
                    var rootNode = target.getRootNodes(data);
                    //console.log(rootNode);
                    $.each(rootNode, function (i, item) {
                        var tr = $('<tr></tr>');
                        tr.addClass('treegrid-' + (j + "_" + i));
                        tr.attr('load', 'true');
                        tr.attr('level', item.level);
                        tr.addClass('unknow');
                        tr.addClass('tree_rootnode');
                        target.renderRow(tr, item);

                        item.isShow = true;
                        tbody.append(tr);
                        target.getChildNodes(data, item, (j + "_" + i), tbody);
                    });
                    target.append(tbody);
                    // 初始化treegrid bug
                    //target.treegrid({
                    //    treeColumn: options.expandColumn ? options.expandColumn : (hasSelectItem ? 1 : 0),//如果有radio或checkbox默认第二列层级显示,当前是在用户未设置的提前下
                    //    expanderExpandedClass: options.expanderExpandedClass,
                    //    expanderCollapsedClass: options.expanderCollapsedClass
                    //});
                    //if (!options.expandAll) {
                    //    target.treegrid('collapseAll');
                    //}
                    $(".treegrid-tbody").find("tr:not(.tree_rootnode)").hide();
                    target.repainExpends();
                },
                error: function (xhr, textStatus) {
                    var _errorMsg = '<tr><td colspan="' + options.columns.length + '"><div style="display: block;text-align: center;">' + xhr.responseText + '</div></td></tr>'
                    tbody.html(_errorMsg);
                }
            });
        }
        /***  初始化图标 ***/
        target.repainExpends = function (tr, reset) {
            var trExpends;
            if (tr) {
                var str = tr.attr('class').split(" ")[0].split("-")[1];
                var cls = "treegrid-parent-" + str;
                trExpends = target.find("tr." + cls);
            }
            else {
                trExpends = target.find("tr");
            }
            /*
            *  isleaf 是否有子数据
            *  load   是否已加载子数据
            */
            if (reset == "true") {
                $.each(trExpends, function (index, item) {
                    if ($(item).attr('isLeaf') == 'true') {
                        $(item).find("span:last-child").removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right').addClass('glyphicon');

                    }
                });
            }
            else {
                $.each(trExpends, function (index, item) {
                    if ($(item).attr('isLeaf') == 'true' && $(item).attr('load') != 'true') {
                        $(item).find("span:last-child").removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right').addClass('glyphicon'); //收缩
                    }
                    else if ($(item).attr('isLeaf') == 'true' && $(item).attr('load') == 'true') {
                        $(item).find("span:last-child").addClass('glyphicon-chevron-down').removeClass('glyphicon-chevron-right').addClass('glyphicon'); //展开
                    }
                    else {
                        if ($(item).hasClass('tree_rootnode')) {
                            $(item).find("span:last-child").removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right').addClass('glyphicon'); //收缩
                        } else {
                            $(item).find("span:last-child").removeClass('glyphicon-chevron-down').removeClass('glyphicon-chevron-right');  //删除图标

                        }
                    }
                });
            }
        }
        /****** 加载子节点数据 start ***************/
        target.loadChilds = function (parentTR, parms) {
            debugger;
            var tbody = $(parentTR).parents(".treegrid-tbody");
            parms = $.extend({}, parms, options.ajaxParams);
            $.ajax({
                type: options.type,
                url: "handler/DeviceMaintainService.ashx?function=childtree",
                data: parms,
                dataType: "JSON",
                success: function (data, textStatus, jqXHR) {
                    var _tr = target.find(".treegrid-" + parms.parentIndex);
                    _tr.attr('load', 'true');
                    target.renderChildRows(data, { "mainId": parms.pid }, parms.parentIndex, _tr);
                    parentTR.removeClass('unknow').addClass('know');
                    target.repainExpends(parentTR);
                },
                error: function (xhr, textStatus) {
                    var _errorMsg = '<tr><td colspan="' + options.columns.length + '"><div style="display: block;text-align: center;">' + xhr.responseText + '</div></td></tr>'
                    tbody.html(_errorMsg);
                },
            });
        }
        /****** 加载子节点数据 end ***************/
        /*自定义扩展方法*/
        var customMethod = {
            collapseNode: function (parentTr) {
                var parentNum = parentTr.attr('class').split(" ")[0].split("-")[1];
                var childCls = "treegrid-parent-" + parentNum;
                var child = $("tr." + childCls);
                if (child.length > 0) {
                    child.hide();
                    for (var i = 0; i < child.length; i++) {
                        if (child.eq(i).attr("isleaf") == "true") {
                            child.eq(i).find("span.treegrid-expander").removeClass("glyphicon-chevron-down").addClass("glyphicon-chevron-right");
                        }
                        this.collapseNode(child.eq(i));
                    }
                }
            },
            expandNode: function (parentTr) {
                var parentNum = parentTr.attr('class').split(" ")[0].split("-")[1];
                var childCls = "treegrid-parent-" + parentNum;
                var child = $("tr." + childCls);
                if (child.length > 0) {
                    child.show();
                    for (var i = 0; i < child.length; i++) {
                        if (child.eq(i).attr("isleaf") == "true") {
                            child.eq(i).find("span.treegrid-expander").removeClass("glyphicon-chevron-right").addClass("glyphicon-chevron-down");
                        }
                        //this.expandNode(child.eq(i));
                    }
                }
            }
        }
        /*初始加载树数据*/
        if (options.url) {
            target.load();
        } else {
            // 通过data属性传递一个数据集合对组件进行初始化,
        }

        /*图标事件绑定*/
        $(document).on('click', 'span.glyphicon-chevron-right', function (e) {
            //console.log("right");
            if ($(this).parent().parent().attr('load') != 'true') {
                //console.log("loadchildren函数下节点图标绑定的事件触发了");
                $(this).removeClass("glyphicon-chevron-right").addClass("glyphicon-chevron-down");
                $(this).parent().parent().addClass("expand").removeClass("collaps");
                target.loadChilds(
                    $(this).parent().parent(),
                    {
                        "pid": $(this).parent().attr('mainid'),
                        "parentIndex": $(this).parent().parent().attr('class').split(" ")[0].split("-")[1],
                        "nowParentIndex": $(this).parent().parent().attr('class').split(" ")[0].split("-")[0]
                    });
            }
            else {
                var parentTr = $(this).parent().parent();
                //var level = parentTr.attr("level");
                //var parentNum = parentTr.attr('class').split(" ")[0].split("-")[1];
                //var childCls = "treegrid-parent-" + parentNum;
                //var child = $("tr." + childCls);
                //if (level == "0" || $(this).parent().parent().hasClass("tree_rootnode")) { //根节点
                //    $(".treegrid-tbody").find("tr:not(.tree_rootnode)").show();                  
                //}
                //else {
                //    child.show();
                //}
                customMethod.expandNode(parentTr);
                $(this).removeClass("glyphicon-chevron-right").addClass("glyphicon-chevron-down");
                $(this).parent().parent().addClass("expand").removeClass("collaps");
                //直属子级图标初始化统一为right
                target.repainExpends(parentTr, "true");
            }
            e.stopPropagation();
        });

        $(document).on('click', 'span.glyphicon-chevron-down', function (e) {
            //console.log("down");
            if ($(this).parent().parent().hasClass("expand")) {
                //获取选中行
                var parentTr = $(this).parent().parent();
                //var level = parentTr.attr("level");
                //if (level == "0" || $(this).parent().parent().hasClass("tree_rootnode")) {
                //    $(".treegrid-tbody").find("tr:not(.tree_rootnode)").hide();
                //}
                //else {
                customMethod.collapseNode(parentTr);
                //}
                console.log(parentTr);
            }
            else {

            }
            $(this).removeClass("glyphicon-chevron-down").addClass("glyphicon-chevron-right");
            $(this).parent().parent().addClass("collaps").removeClass("expand");
            e.stopPropagation();
        });

        $(document).on('click', '.treegrid-tbody tr', function () {
            $(".treegrid-tbody tr").removeClass("checked-item");
            var id = $(this).children(0).attr("mainid");
            $(this).addClass("checked-item");
            parent.$("#FullBodyContent_hdSelectedNodeId").val(id);
            $("#treeId").val(id);
        })
        return target;
    };



    // 组件方法封装
    $.fn.myAjaxTreeTable.methods = {
        // 返回选中记录的id
        getSelections: function (target) {
            var _ipt = target.find("tbody").find("tr").find("input[name='select_item']:checked");
            var chk_value = [];
            if (_ipt.attr("type") == "radio") {
                chk_value.push({ id: _ipt.val() });
            } else {
                _ipt.each(function (_i, _item) {
                    chk_value.push({ id: $(_item).val() });
                });
            }
            return chk_value;
        },
        // 刷新记录
        refresh: function (target, parms) {
            if (parms) {
                target.load(parms);
            } else {
                target.load();
            }
        },
        // 重置表格视图
        resetHeight: function (target, height) {
            target.find("tbody").css("height", height + 'px');
        }
    };

    $.fn.myAjaxTreeTable.defaults = {
        id: 'id',// 选取记录返回的值
        pid: 'pid',// 用于设置父子关系
        rootidValue: null,//设置根节点id值----可指定根节点,默认为null,"",0,"0"
        data: [], // 构造table的数据集合,本地测试可以设置具体数据
        type: "GET", // 请求数据的ajax类型
        url: null, // 请求数据的ajax的url
        ajaxParams: {}, // 请求数据的ajax的data属性
        expandColumn: null,// 在哪一列上面显示展开按钮
        expandAll: false, // 是否全部展开
        striped: false, // 是否各行渐变色
        columns: [],
        toolbar: null,//顶部工具条
        height: 0,
        expanderExpandedClass: 'glyphicon glyphicon-chevron-down',// 展开的按钮的图标
        expanderCollapsedClass: 'glyphicon glyphicon-chevron-right'// 缩起的按钮的图标
    };
})(jQuery);

效果图:

原文地址:https://www.cnblogs.com/niesiao/p/9626483.html