• 我的开源框架之树控件


    需求:

    1.根据无限级的树形结构的json生成树菜单

    2.树样式可以是图标类型和简单类型

    3.可以自定义节点的图标

    4.支持复选框

    5.支持懒加载方式请求数据

    6.支持节点点击事件

    7.只有右键菜单【未实现】

    8.支持拖拽调整节点【未实现】

    实现图例

    客户代码

     1 <body>
     2     <div id="Container" style="padding:10px; margin:0 auto;800px;height:300px;padding-top:10px;padding-left:100px">
     3         <ul id="tree"></ul>
     4     </div>
     5     <script type="text/javascript">
     6         function getAllCheckedNodes() {
     7             var nodes =  tree.tree('getCheckNodes', '');
     8             alert(JSON.stringify(nodes));
     9         }
    10         var data = [{
    11             "id1": "0",
    12             "text1": "菜单",
    13             "checked": true,
    14             "iconCls": "icon-ok",
    15             "children": [{
    16                 "id1": "0_1",
    17                 "text1": "子菜单1",
    18                 "checked": true,
    19                 "iconCls": "icon-save"
    20             }, {
    21                 "id1": "0_2",
    22                 "text1": "子菜单2",
    23                 "checked": true,
    24                 "iconCls": "icon-ok"
    25             }
    26             ]
    27         },{
    28             "id1": '2',
    29             "text1": "计算机语言",
    30             "closed": false,
    31             "children": [{
    32                 "id1": "2_1",
    33                 "text1": "Java",
    34                 "children": [{
    35                     "id1": '2_1_1',
    36                     "text1": 'j2ee'
    37                 }, {
    38                     "id1": '2_1_2',
    39                     "text1": 'j2me',
    40                     "checked": true,
    41                     "iconCls": "icon-ok"
    42                 }, {
    43                     "id1": '2_1_3',
    44                     "text1": 'jsp'
    45                 }]
    46                 }, {
    47                     "id1": "2_2",
    48                     "text1": "C#"
    49                 }]
    50         }];
    51         var tree;
    52         $(function () {
    53             tree = $("#tree").tree({
    54                 onClick: function (data) {
    55                     console.log(JSON.stringify(data));
    56                     alert("click");
    57                 },
    58                 animate: true,
    59                 isPlain: false,
    60                 checkbox: true,
    61                 textField: 'text1',
    62                 idField: 'id1',
    63                 //data: data
    64                 lazy:true,                
    65                 url: 'testServer/jsonQuestTest.ashx?flag=tree',
    66                 onLoadSuccess:function(data){
    67                     console.log("服务器数据返回:"+ JSON.stringify(data));
    68                 }                
    69             });
    70         });
    71     </script>
    72 </body>

    组件代码:

      1 /**************************************************************
      2 *作者:hjwen
      3 *电邮:hjwen88@126.com
      4 *版本:1.0
      5 *版权许可:中国通用开源许可协议V1.0
      6 *说明:tree组件
      7 ***************************************************************/
      8 (function ($) {
      9     var isPlain = false, checkbox = false, animate = false, lazy = false; textField = 'text', idField = 'id', url="";
     10     var treeDataObj = null; var treeOpts = null;
     11     var onLoadSuccess = null;//加载成功
     12     function renderHtml(target) {
     13         target.addClass('tree');
     14         treeOpts = target.data('settings');       
     15         if (treeOpts.data == null) {
     16             alert("treeOpts.data 是必须的!");
     17             return;
     18         }
     19         treeDataObj = treeOpts.data;
     20         target.parent().css("overflow", "auto");
     21         isPlain = treeOpts.isPlain;
     22         checkbox = treeOpts.checkbox;
     23         animate = treeOpts.animate;
     24         lazy = treeOpts.lazy;
     25         url = treeOpts.url;
     26         textField = treeOpts.textField;
     27         idField = treeOpts.idField;
     28         var treeJson = treeOpts.data;
     29         var ctlData={isRoot:true,path:'',pid:'',isLastf:false,isFirstf:false,isRootFirst:false,isRootLast:false};
     30         loopInitCreate(treeJson, 1, target, ctlData);
     31     };
     32     function loopInitCreate(treeJson, treeDeep, target,ctlData) {
     33         var lastItem;
     34         $.each(treeJson, function (i, node) {
     35             var children = node.children;
     36             node.idx = i;
     37             node.pid = ctlData.pid;
     38             var controlData = {//控制参数
     39                 isRoot: ctlData.isRoot,//是否是树根
     40                 isFirst: false,//是否是第一个节点
     41                 isLast: false,//是否是最后一个节点
     42                 path: ctlData.path + i,//树路径,用于数据搜索,避免全树扫描性能问题
     43                 isLeaf: false,//是否是子叶
     44                 isLastf: ctlData.isLastf,//父元素是否为最后一个 ,第一级没有父元素为false
     45                 isFirstf: ctlData.isFirstf,//父元素是否为第一个 ,第一级没有父元素为false
     46                 treeDeep: treeDeep,//树深度
     47                 isRootFirst: ctlData.isRootFirst,//是否是根第一个节点,用于控制节点图标和补充线的样式
     48                 isRootLast: ctlData.isRootLast//是否是根最后一个节点,用于控制节点图标和补充线的样式
     49             };
     50             if (i == 0) {
     51                 if (ctlData.isRoot)
     52                     controlData.isRootFirst = true;
     53                 controlData.isFirst = true;
     54             }
     55             if (i == treeJson.length - 1) {
     56                 controlData.isLast = true;
     57                 if (ctlData.isRoot)
     58                     controlData.isRootLast = true;
     59             }
     60             if (typeof children != 'undefined' && $.isArray(children)) {
     61                 var li = $("<li class="tree_li"></li>").appendTo(target);
     62                 if (children.length == 0)
     63                     node.closed = true;
     64                 lastItem = loopCreateTree(node, li, controlData);
     65             } else {//子叶   
     66                 controlData.isLeaf = true;
     67                 lastItem = createLeafNode(node, target, controlData);
     68             }
     69         });
     70         var tmpDeep = lastItem.attr("treedeep");
     71         var isleaf = lastItem.attr("isleaf");
     72         if (isleaf == 'true'){
     73             if(lastItem.attr("isrootlast")=='true')
     74                 lastItem.children("div:lt(" + tmpDeep + ")").removeClass("tree_line_all").addClass("tree_line_up");
     75         }else {
     76             if (lastItem.attr("isclose") == 'true'){
     77                 lastItem.children("div:lt(" + tmpDeep + ")").removeClass("tree_collapsable_center").addClass("tree_collapsable_up");
     78                 lastItem.children("div:lt(" + (parseInt(tmpDeep)-1) + ")").removeClass("tree_line_all").addClass("tree_line_up");
     79             }                
     80             else
     81                 lastItem.children("div:lt(" + tmpDeep + ")").removeClass("tree_expandable_center").addClass("tree_expandable_up");
     82         }
     83     }
     84     /**********私有方法开始********************/
     85     /****远程加载数据*****/
     86     function queryData(params,loadingContaner, fn) {
     87         var ajaxopt = {
     88             url: url,
     89             params: params,
     90             loadingContainer: loadingContaner,
     91             okdeal: function (data) {
     92                 var arr = eval(data);
     93                 fn(arr);
     94                 if (typeof onLoadSuccess === 'function') {
     95                     onLoadSuccess(arr);
     96                 }
     97             }
     98         };        
     99         $.myui.ajaxRequest(ajaxopt);
    100     };
    101     /*****
    102     *修改树数据的checked属性,注意非子叶节点的checked只做参考
    103     *@param path :节点的树路径,根据路径查找节点,避免全树搜索的性能开销
    104     *@param checked 是否选中
    105     ******/
    106     function modifyCheckAttr(path, checked) {
    107         var pathArr = path.split('_');  
    108         //利用setTimeout模拟开启一个更新数据的线程,加快处理速度
    109         setTimeout(function () {           
    110             //console.log("点击前数据=" + JSON.stringify(treeDataObj));
    111             loopCheckAttr(treeDataObj, pathArr, checked == 'true');
    112             //console.log("更新后数据=" + JSON.stringify(treeDataObj));
    113         },0);  
    114     };
    115     function loopCheckAttr(dataArr, pathArr, checked) {
    116         for (var i = 0, len = dataArr.length; i < len; ++i) {
    117             if (pathArr[0] == i) {//已经找到 
    118                 dataArr[i].checked = checked;
    119                 if (pathArr.length > 1) {//根据path往下搜寻到末节点
    120                     if (typeof dataArr[i].children != 'undefined' && $.isArray(dataArr[i].children)) {//如果有子集合
    121                         var tempArr = [];
    122                         for (var j = 0; j < pathArr.length; j++) {
    123                             if (j > 0)
    124                                 tempArr.push(pathArr[j]);
    125                         }
    126                         loopCheckAttr(dataArr[i].children, tempArr, checked);
    127                     }
    128                 } else {//如果已经找到路径的末点,并且点击的是非子叶节点则需要再往下更新数据                    
    129                     if (typeof dataArr[i].children != 'undefined' && $.isArray(dataArr[i].children)) {
    130                         loopChildrenAttr(dataArr[i].children, checked);
    131                     }
    132                 }
    133                 break;
    134             }
    135         }
    136     };
    137     /****根据path获取点击节点的数据***/
    138     function getNodeByPath(dataArr, pathArr) {
    139         for (var i = 0, len = dataArr.length; i < len; ++i) {
    140             if (pathArr[0] == i) {//已经找到               
    141                 if (pathArr.length > 1) {//根据path往下搜寻到末节点
    142                     if (typeof dataArr[i].children != 'undefined' && $.isArray(dataArr[i].children)) {
    143                         var tempArr = [];
    144                         for (var j = 0; j < pathArr.length; j++) {
    145                             if (j > 0)
    146                                 tempArr.push(pathArr[j]);
    147                         }
    148                         return getNodeByPath(dataArr[i].children, tempArr);
    149                     } 
    150                 } else {
    151                     return dataArr[i];
    152                 }
    153                 break;
    154             }
    155         }
    156     };
    157     /********根据path获取checked=true节点的数据***********/
    158     function getCheckedNodeByPath(dataArr, pathArr) {
    159         var res = [];
    160         if (pathArr.length ==1 && pathArr[0] == "") {
    161             $.each(dataArr, function (i, node) {
    162                 if (typeof node.children != 'undefined' && $.isArray(node.children)) {
    163                     loopCheckedChildren(res, node.children);
    164                 } else {
    165                     if (node.checked)
    166                         res.push(node);
    167                 }
    168             });
    169         } else {
    170             var node = getNodeByPath(dataArr, pathArr);
    171             if (typeof node.children != 'undefined' && $.isArray(node.children)) {
    172                 loopCheckedChildren(res, node.children);
    173             } else {
    174                 if (node.checked)
    175                     res.push(node);
    176             }
    177         }
    178         return res;
    179     };
    180     function loopCheckedChildren(res, nodes) {
    181         $.each(nodes, function (i,node) {
    182             if (typeof node.children != 'undefined' && $.isArray(node.children)) {
    183                 loopCheckedChildren(res, node.children);
    184             } else {
    185                 if (node.checked)
    186                     res.push(node);
    187             }
    188         });
    189     };
    190     function loopChildrenAttr(children, checked) {
    191         $.each(children, function (j, node) {
    192             node.checked = checked;
    193             if (typeof node.children != 'undefined' && $.isArray(node.children)) {
    194                 loopChildrenAttr(node.children, checked);
    195             }
    196         });
    197     };
    198     /****
    199     *复选框点击
    200     ****/
    201     function chkClick(e) {
    202         var t = $(this);
    203         var checked;
    204         var chkedString='true';
    205         var p = t.parent("div");
    206         if (t.hasClass("tree_chk_check_all"))//注意点击时,发现为选中状态的,将会变更为非选择状态
    207             chkedString = 'false';
    208         modifyCheckAttr(p.attr("path"), chkedString);            
    209         if (p.attr("isleaf") == 'true') {//子叶点击          
    210             if (t.hasClass("tree_chk_check_all")) {
    211                 checked = false;
    212                 p.attr("checkstate", "-1");
    213                 t.removeClass("tree_chk_check_all").addClass("tree_chk_uncheck");
    214             } else {
    215                 checked = true;
    216                 p.attr("checkstate", "1");
    217                 t.removeClass("tree_chk_uncheck").addClass("tree_chk_check_all");
    218             }
    219             loopCheckStyle(p.parent("li"), checked, 1);
    220         } else {
    221             var chkstate = p.attr("checkstate");
    222             if (chkstate == "1") {//如果是全选,在变为全取消
    223                 checked = false;
    224                 p.attr("checkstate", "-1");
    225                 p.attr("checkedcount", "0");
    226                 t.removeClass("tree_chk_check_all").addClass("tree_chk_uncheck");
    227                 //向下修改子节点
    228                 loopCheckChildStyle(p.next().children("li"), checked);
    229                 //向上修改父节点
    230                 if (p.attr("isroot")=='false')
    231                     loopCheckStyle(p.parent("li"), checked, 1)
    232             } else {//变为全选状态
    233                 checked = true;
    234                 p.attr("checkstate", "1");
    235                 p.attr("checkedcount", p.attr("childcount"));
    236                 t.removeClass("tree_chk_uncheck").removeClass("tree_chk_check").addClass("tree_chk_check_all");
    237                 //向下修改子节点
    238                 loopCheckChildStyle(p.next().children("li"), checked);
    239                 //向上修改父节点
    240                 if (p.attr("isroot") == 'false')
    241                     loopCheckStyle(p.parent("li"), checked, 1)
    242             } 
    243         }
    244         if (e && e.stopPropagation)
    245             e.stopPropagation();
    246         else
    247             window.event.cancelBubble = true;
    248     };
    249     function loopCheckChildStyle(childrens,checked) {
    250         $.each(childrens, function (i, node) {
    251             var $node = $(node).children("div");
    252             var chkIoc = $node.children(".tree_chk_ioc");
    253             if (checked) {
    254                 $node.attr("checkstate","1");
    255                 chkIoc.removeClass("tree_chk_uncheck").removeClass("tree_chk_check").addClass("tree_chk_check_all");
    256                 if ($node.attr("isleaf") == 'false') {//非子叶节点
    257                     $node.attr("checkedcount", $node.attr("childcount"));
    258                     loopCheckChildStyle($node.next().children("li"), checked);
    259                 }
    260             } else {
    261                 $node.attr("checkstate", "-1");
    262                 chkIoc.removeClass("tree_chk_check_all").removeClass("tree_chk_check").addClass("tree_chk_uncheck");
    263                 if ($node.attr("isleaf") == 'false') {//非子叶节点
    264                     $node.attr("checkedcount", "0");
    265                     loopCheckChildStyle($node.next().children("li"), checked);
    266                 }
    267             }           
    268         });
    269     }
    270     /***
    271    *递归check样式检查,并根据check状态修改图标样式
    272    *@param curLi 子叶项标签
    273    *@param checked 复选框 选中/不选中
    274    *@param count 加 减数量 
    275    ****/
    276     function loopCheckStyle(curLi, checked, count) {
    277         var p_ul = curLi.parent("ul");
    278         var titleObj = p_ul.prev();
    279         var fchkCount = parseInt(titleObj.attr('checkedcount'));
    280         var fchildCount = parseInt(titleObj.attr('childcount'));
    281         var fchkState = titleObj.attr('checkstate');
    282         var chkBoxDiv = titleObj.children(".chk_ioc");
    283         if (checked) {//如果是选中
    284             fchkCount = fchkCount + count;
    285             if (fchkCount > fchildCount)
    286                 fchkCount = fchildCount;
    287             titleObj.attr('checkedcount', fchkCount);
    288             // 修改父元素的 checkedcount checkstate 
    289             if (fchildCount == fchkCount) {
    290                 chkBoxDiv.removeClass("tree_chk_check");
    291                 chkBoxDiv.removeClass("tree_chk_uncheck");
    292                 chkBoxDiv.addClass("tree_chk_check_all");
    293                 titleObj.attr('checkstate', '1');
    294             } else {
    295                 chkBoxDiv.removeClass("tree_chk_uncheck");
    296                 chkBoxDiv.removeClass("tree_chk_check_all");
    297                 chkBoxDiv.addClass("tree_chk_check");
    298                 titleObj.attr('checkstate', '0');
    299             }
    300         } else {//取消选中
    301             fchkCount = fchkCount - count;
    302             if (fchkCount < 0)
    303                 fchkCount = 0;
    304             titleObj.attr('checkedcount', fchkCount);
    305             if (fchkCount == 0) {
    306                 titleObj.attr('checkstate', '-1');
    307                 chkBoxDiv.removeClass("tree_chk_check");
    308                 chkBoxDiv.removeClass("tree_chk_check_all");
    309                 chkBoxDiv.addClass("tree_chk_uncheck");
    310             } else {
    311                 chkBoxDiv.removeClass("tree_chk_uncheck");
    312                 chkBoxDiv.removeClass("tree_chk_check_all");
    313                 chkBoxDiv.addClass("tree_chk_check");
    314                 titleObj.attr('checkstate', '0');
    315             }
    316         } 
    317         //递归修改上一级父元素的状态
    318         if (titleObj.attr("isroot") == 'false') {
    319             count = 0;
    320             if (titleObj.attr("checkstate") == "1" || titleObj.attr("checkstate") == "-1") {
    321                 count = 1;
    322             }
    323             loopCheckStyle(titleObj.parent("li"), checked, count);
    324         }        
    325     };
    326     /****
    327     *节点点击,展开/收起
    328     *****/
    329     function nodeClick(e) {
    330         var t = $(this);
    331         var p = t.parent("div");
    332         var ul = p.next();
    333         if (p.attr("isclose") == 'false') {//收起
    334             p.children(".ioc_ioc").removeClass("tree_node_file_open").addClass("tree_node_file_close");//改变文件夹样式
    335             if (p.attr("isrootfirst") == 'true' && p.attr("treedeep") == '1') {//如果是根节点
    336                 if (p.attr("islast")=='true')
    337                     t.addClass("tree_collapsable_all");
    338                 else
    339                     t.addClass("tree_collapsable_down");
    340 
    341                 t.removeClass("tree_expandable_down");
    342             } else {
    343                 t.removeClass("tree_expandable_center");
    344                 if (p.attr("isrootlast") == 'true' && p.attr("islast") == 'true') {
    345                     if (p.attr("isfirst") == 'true')
    346                         t.addClass("tree_collapsable_all");
    347                     else
    348                         t.addClass("tree_collapsable_up");
    349                 } else {
    350                     t.addClass("tree_collapsable_center");
    351                 }
    352             }
    353             if (p.attr("isrootlast") == 'true' && p.attr("islast") == 'true' && p.attr("islastf") == 'true') {
    354                 p.children(".line_ioc").removeClass("tree_line_all").addClass("tree_line_up");
    355             }
    356             if (animate) {
    357                 ul.hide(300);
    358             } else {
    359                 ul.hide();
    360             }
    361             p.attr("isclose", 'true');
    362         } else {//展开
    363             p.children(".ioc_ioc").removeClass("tree_node_file_close").addClass("tree_node_file_open");
    364             if (p.attr("isrootfirst") == 'true' && p.attr("treedeep") == '1') {//如果是根节点
    365                 t.removeClass("tree_collapsable_down");
    366                 t.addClass("tree_expandable_down");
    367             } else {
    368                 if (p.attr("islast") == "true"){
    369                     t.removeClass("tree_collapsable_up");
    370                     t.prevAll().removeClass("tree_line_up").addClass("tree_line_all");
    371                 }                    
    372                 else
    373                     t.removeClass("tree_collapsable_center");
    374                 t.addClass("tree_expandable_center");
    375             }
    376             if (p.attr("isrootlast") == 'true' && p.attr("islast") == 'true' && p.attr("islastf") == 'true') {
    377                 p.children(".line_ioc").removeClass("tree_line_up").addClass("tree_line_all");
    378             }
    379             if (animate) {
    380                 ul.show(300);
    381             } else {
    382                 ul.show();
    383             }
    384             p.attr("isclose", 'false');
    385             if (lazy&&url!="") {
    386                 if (p.attr("childcount") == '0') {
    387                     var target = p.next("ul");
    388                     var loadingContaner = $("<li></li>").appendTo(target);
    389                     queryData("pid=" + p.attr("id"), loadingContaner, function (data) {
    390                         //将查询到的数据补充到treeDataObj,采用settimeout
    391                         setTimeout(function () {
    392                             var pathArr = p.attr("path").split("_");
    393                             //console.log("添加前数据=" + JSON.stringify(treeDataObj));
    394                             var findedNode = getNodeByPath(treeDataObj, pathArr);
    395                             findedNode.children = data;
    396                             //console.log("添加后数据=" + JSON.stringify(treeDataObj));
    397                         }, 0);
    398                         loadingContaner.remove();
    399                         p.attr("childcount", data.length);
    400                         var ctlData = {
    401                             isRoot: false,
    402                             path: p.attr("path") + "_",
    403                             pid: p.attr("id"),
    404                             isLastf: p.attr("islast")=='true',
    405                             isFirstf: p.attr("isfirst") == 'true',
    406                             isRootFirst: p.attr("isrootfirst") == 'true',
    407                             isRootLast: p.attr("isrootlast") == 'true'
    408                         };
    409                         if (p.attr("isroot") == 'true') {
    410                             ctlData.isRootFirst = ctlData.isFirstf;
    411                             ctlData.isRootLast = ctlData.isLastf;
    412                         }
    413                         loopInitCreate(data, parseInt(p.attr("treeDeep")) + 1, target, ctlData);
    414                     });
    415                 }             
    416             }
    417         }
    418         if (e && e.stopPropagation)
    419             e.stopPropagation();
    420         else
    421             window.event.cancelBubble = true;
    422     }
    423     /****
    424    *创建一个子节点
    425    *@param node 节点数据
    426    *@param target 节点目标容器
    427    *@param controlData 控制ui的数据
    428    *****/
    429     function createLeafNode(node, target, controlData) {
    430         /***********线样式***************/
    431         //根据树深度补充外围线 
    432         var lineCls = '', help = 1, fixLineDiv = '';
    433         if (controlData.isLast && controlData.isFirst && controlData.isRoot) {//只有一个子叶节点
    434             lineCls = "";
    435         } else {
    436             if (controlData.isLast && controlData.isRoot) {
    437                 lineCls = "tree_line_up";
    438             } else if (controlData.isFirst && controlData.isRoot) {
    439                 lineCls = "tree_line_down";
    440             } else {
    441                 if (controlData.isLast) {
    442                     lineCls = "tree_line_up";
    443                 } else {
    444                     lineCls = "tree_line_center";
    445                 }
    446             }
    447         }
    448         while (help <= controlData.treeDeep) {
    449             if (help == controlData.treeDeep) {//自身列
    450                 fixLineDiv = fixLineDiv + "<div class="tree_ioc_item tree_line_ioc " + lineCls + ""></div>";
    451             } else {
    452                 fixLineDiv = fixLineDiv + "<div class="tree_ioc_item tree_line_ioc tree_line_all"></div>";
    453             }
    454             help++;
    455         }
    456         /**************图标样式****************/
    457         var iconDiv = '';
    458         if (!isPlain) {//不是简单样式
    459             var iconCls = 'tree_file_ioc tree_node_leaf';//默认的图标样式
    460             if (typeof node.iconCls == 'string') {
    461                 iconCls = node.iconCls;
    462                 iconDiv = "<div style="background-position:0 2px;" class="tree_ioc_item " + iconCls + ""></div>";
    463             } else {
    464                 iconDiv = "<div class="tree_ioc_item " + iconCls + ""></div>";
    465             }
    466         }
    467         /**************复选框样式***************/
    468         var chkBoxDiv = '', checkstate = '-1';
    469         if (checkbox) {
    470             var checked = node.checked;
    471             var chkCls = 'tree_chk_uncheck';
    472             if (typeof checked == 'boolean' && checked) {
    473                 chkCls = 'tree_chk_check_all';
    474                 checkstate = '1';
    475             } else {
    476                 node.checked = false;//客户代码中没有checked,则补充上
    477             }
    478             chkBoxDiv = "<div class='tree_ioc_item tree_chk_ioc " + chkCls + "'></div>";
    479         }
    480         var id = node[idField];
    481         var text = node[textField];
    482         var li_html = "<li class="tree_li"><div treedeep='" + controlData.treeDeep + "' isfirstf='" + controlData.isFirstf + "' islastf='" + controlData.isLastf + "' isrootlast='" + controlData.isRootLast + "' isrootfirst='" + controlData.isRootFirst + "' path='" + controlData.path + "'  checkstate='" + checkstate + "' pid='" + node.pid + "' isleaf='true' isLast='" + controlData.isLast + "' isfirst='" + controlData.isFirst + "' isroot='" + controlData.isRoot + "' treedeep='" + controlData.treeDeep + "' id='" + id + "' class='tree_ioc_wrap'>" + fixLineDiv + iconDiv + chkBoxDiv + "<div class='tree_li_text'>" + text + "</div></div></li>";
    483         var li = $(li_html).appendTo(target);
    484         var wrap = li.children("div");
    485         if (typeof treeOpts.onClick == 'function') {
    486             wrap.bind('click', function () {
    487                var data = getNodeByPath(treeDataObj,$(this).attr("path").split("_"));
    488                treeOpts.onClick(data);
    489             });
    490         }     
    491         if (checkbox) {
    492             var checked = node.checked;
    493             if (typeof checked == 'boolean' && checked) {
    494                 loopCheckStyle(li, true, 1);
    495             }
    496             wrap.children(".tree_chk_ioc").bind('click', chkClick);
    497         }
    498         return li.children("div");
    499     };
    500 
    501     /****
    502    *循环递归创建一个父节点,这里肯定是子树
    503    *@param node 节点数据
    504    *@param target 节点目标容器
    505    *@param controlData 控制ui的数据
    506    *****/
    507     function loopCreateTree(nodef, target, controlData) {
    508         var treeJson = nodef.children;
    509         var iconDiv = "";
    510         var closed = false;
    511         if (typeof nodef.closed == 'boolean')
    512             closed = nodef.closed;
    513         /************文件夹样式*****************/
    514         var lineCls, hideCls, help = 1, fixLineDiv = '', fixLineCls = 'tree_line_all';
    515         if (closed) {//闭合状态
    516             hideCls = 'display:none';
    517             if (controlData.isRoot && controlData.isFirst) {//根目录第一个节点            
    518                lineCls = 'tree_collapsable_down';
    519             } else {
    520                 if (controlData.isFirst) {
    521                     lineCls = 'tree_collapsable_down';
    522                 } else {
    523                     lineCls = 'tree_collapsable_center';
    524                 }
    525             }
    526             //闭合状态下,要处理最后一个关闭节点的外围补充线样式问题
    527             if (controlData.isRootLast && controlData.isLast) {
    528                 fixLineCls = 'tree_line_up';
    529                 lineCls = 'tree_collapsable_up';
    530             }
    531         } else {//打开状态
    532             hideCls = 'display:block';
    533             if (controlData.isRoot && controlData.isFirst) {//根目录第一个节点               
    534                 lineCls = 'tree_expandable_down';             
    535             } else {
    536                 if (controlData.isFirst) {
    537                     lineCls = 'tree_expandable_center';
    538                 } else {
    539                     lineCls = 'tree_expandable_center';
    540                 }
    541             }
    542         }
    543         //根据树深度补充外围线            
    544         while (help <= controlData.treeDeep) {
    545             if (help == controlData.treeDeep) {
    546                 fixLineDiv = fixLineDiv + "<div class="node_ioc tree_ioc_item tree_line_ioc " + lineCls + ""></div>"
    547             } else {
    548                 fixLineDiv = fixLineDiv + "<div class="line_ioc tree_ioc_item tree_line_ioc " + fixLineCls + ""></div>";
    549             }
    550             help++;
    551         }
    552         /**************图标样式 *****************/
    553         if (!isPlain) {//不是简单样式
    554             var tmpCls;
    555             if (closed) {
    556                 tmpCls = "tree_node_file_close";
    557             } else {
    558                 tmpCls = "tree_node_file_open";
    559             }
    560             var iconCls = 'tree_file_ioc ' + tmpCls;//默认的图标样式
    561             iconDiv = "<div class="ioc_ioc tree_ioc_item " + iconCls + ""></div>";
    562         }
    563         /**************复选框******************/
    564         var chkBoxDiv = '';
    565         var checkstate = "-1"; //-1不选择,0部分选择,1全部选择
    566         var chkAll = false;
    567         if (checkbox) {
    568             var chkCls = 'tree_chk_uncheck';
    569             chkBoxDiv = "<div class='chk_ioc tree_ioc_item tree_chk_ioc " + chkCls + "'></div>";
    570             if (typeof nodef.checked == 'boolean')
    571                 chkAll = nodef.checked;
    572         }
    573         var id = nodef[idField];
    574         var text = nodef[textField];
    575         var headHtml = "<div treedeep='" + controlData.treeDeep + "' isclose='" + closed + "' isfirstf='" + controlData.isFirstf + "' islastf='" + controlData.isLastf + "' isrootlast='" + controlData.isRootLast + "' isrootfirst='" + controlData.isRootFirst + "' path='" + controlData.path + "' checkstate='" + checkstate + "' checkedcount='0' childcount='" + treeJson.length + "' isleaf='false' pid='" + nodef.pid + "' islast='" + controlData.isLast + "' isfirst='" + controlData.isFirst + "' isroot='" + controlData.isRoot + "' treedeep='" + controlData.treeDeep + "' id='" + id + "' class="tree_ioc_wrap">" + fixLineDiv + iconDiv + chkBoxDiv + "<div class='tree_li_text'>" + text + "</div></div>";
    576         var headObj = $(headHtml).appendTo(target);
    577         if (typeof treeOpts.onClick == 'function') {
    578             headObj.bind('click', function () {
    579                 var data = getNodeByPath(treeDataObj,$(this).attr("path").split("_"));
    580                 treeOpts.onClick(data);
    581             });
    582         }  
    583         if (checkbox) {
    584             headObj.children(".chk_ioc").bind('click', chkClick);
    585         }
    586         headObj.children(".node_ioc").bind('click', nodeClick);
    587         var ul = $("<ul  style='" + hideCls + "'></ul>").appendTo(target);
    588         var chkCount = 0;
    589         $.each(treeJson, function (i, node) {
    590             var children = node.children;
    591             node.pid = id;
    592             node.idx = i;
    593             var cdata = { //控制参数
    594                 isRoot: false,
    595                 isFirst: false,
    596                 isLast: false,
    597                 path: controlData.path + "_" + i,
    598                 isLeaf: false,
    599                 isLastf: false,
    600                 isFirstf: false,
    601                 treeDeep: controlData.treeDeep + 1,
    602                 isRootFirst: controlData.isRootFirst,
    603                 isRootLast: controlData.isRootLast
    604             };
    605             if (checkbox) {
    606                 if (chkAll)
    607                     node.checked = true;
    608                 if (node.checked)
    609                     chkCount++;
    610             }
    611             if (controlData.isLast)
    612                 cdata.isLastf = true;
    613             if (controlData.isFirst)
    614                 cdata.isFirstf = true;
    615             if (i == treeJson.length - 1)
    616                 cdata.isLast = true;
    617             if (i == 0)
    618                 cdata.isFirst = true;
    619             if (typeof children != 'undefined' && $.isArray(children)) {
    620                 var li = $("<li class="tree_li"></li>").appendTo(ul);
    621                 if (children.length == 0)
    622                     node.closed = true;
    623                 headObj = loopCreateTree(node, li, cdata);
    624             } else {
    625                 headObj = createLeafNode(node, ul, cdata);
    626             }
    627         });
    628         if (chkCount == treeJson.length)
    629             nodef.checked = true;
    630         else
    631             nodef.checked = false;
    632         return headObj;
    633     };
    634     /**********私有方法结束*******************/
    635     var methods = {
    636         init: function (options) {
    637             if ($.isArray(options)) {
    638                 options = {
    639                     data: options
    640                 };
    641             }
    642             return this.each(function () {
    643                 var $this = $(this);
    644                 var settings = $this.data('settings');
    645                 if (typeof (settings) == 'undefined') {
    646                     settings = $.extend({}, $.fn.tree.defaults, options);
    647                     $this.data('settings', settings);
    648                 } else {
    649                     settings = $.extend({}, settings, options);
    650                 }
    651                 //创建ui布局
    652                 if (settings.url != '') {//远程请求数据
    653                     onLoadSuccess = settings.onLoadSuccess;
    654                     url = settings.url;
    655                     queryData('',$this, function (data) {
    656                         settings.data = data;
    657                         renderHtml($this);
    658                     });
    659                 } else {
    660                     renderHtml($this);
    661                 }               
    662                 if ($.myui.isDebug) {
    663                     $.myui.log("jQuery.tree init finish......");
    664                 }
    665             });
    666         },
    667         destroy: function (options) {
    668             return $(this).each(function () {
    669                 var $this = $(this);
    670                 $this.removeData('settings');
    671             });
    672         },
    673         /****
    674         *@params path 节点路径,path为空时则获取整个树所有checked状态的节点
    675         &@return 节点数组
    676         *****/
    677         getCheckNodes: function (path) {
    678             var pathArr = path.split('_');
    679             return getCheckedNodeByPath(treeDataObj, pathArr);
    680         }
    681     };
    682     /********************
    683     *组件的构造函数
    684     *********************/
    685     $.fn.tree = function () {
    686         var method = arguments[0];
    687         if (methods[method]) {
    688             method = methods[method];
    689             arguments = Array.prototype.slice.call(arguments, 1);
    690         } else if (typeof (method) == 'object' || !method) {
    691             if ($.myui.isDebug) {
    692                 $.myui.log("jQuery.tree init.....");
    693             }
    694             method = methods.init;
    695         } else {
    696             $.error('Method ' + method + ' does not exist on jQuery.tree');
    697             return this;
    698         }
    699         return method.apply(this, arguments);
    700     };
    701     /********************
    702     *组件的默认配置值
    703     *********************/
    704     $.fn.tree.defaults = {
    705         textField: 'text',//菜单名称字段,默认为text
    706         idField: 'id',//菜单id字段,默认为id
    707         url: '',//远程加载数据地址
    708         lazy:false,//延时加载,当设置为true时,点击节点展开时,如果子元素为空则根据节点id发起请求加载子节点集合
    709         data: null,//树json数据    
    710         isPlain: false,//true 为简单无图标样式
    711         checkbox: false,//是否需要选择框
    712         animate: true,//是否需要动画
    713         onLoadSuccess: null,//加载成功
    714         onClick: null,//点击事件 
    715         isDrag: false,//是否可以拖拽调整节点
    716         onPreDrag: null,//拖拽前 未实现
    717         onDrag: null,//拖拽释放后未实现,
    718         contextMenu: false //右键菜单未实现
    719     };
    720 })(jQuery);
  • 相关阅读:
    ManualResetEvent详解
    MEF搜索范围
    ThreadStart和ParameterizedThreadStart区别
    快速理解C#高级概念(一) Delegate委托
    c# 多线程 --Mutex(互斥锁)
    sql server 得到数据库字典
    遇到的坑:在线用户统计的实现
    asp.net core 使用EF7 Code First 创建数据库,同时使用命令创建数据库
    使用cachemanager做缓存(Session的缓存)
    C# web api返回类型设置为json的两种方法
  • 原文地址:https://www.cnblogs.com/hjwen/p/3886918.html
Copyright © 2020-2023  润新知