我的开源框架之树控件

需求:

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

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

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

4.支持复选框

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

6.支持节点点击事件

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

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

实现图例

客户代码

 1 <body>
 2     <div id="Container" style="padding:10px; margin:0 auto;width: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 *电邮:[email protected]
  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);

我的开源框架之树控件

时间: 2024-10-13 18:44:46

我的开源框架之树控件的相关文章

我的开源框架之面板控件

需求: (1)可伸缩.扩大.缩小 (2)可自定义工具栏(依赖工具栏控件),工具栏可定义位置 (3)可加装远程数据 实现图例 客户代码 function addMoreTools() { var toolbar = panel.panel("getToolbar"); toolbar.toolbar('addButtons', [ { id: 'btn_5', text: '按钮5', iconCls: 'icon-edit', handler: function () { alert(

我的开源框架之Accordion控件

需求: (1)实现手风琴面板控件,支持静态HTML与JSON方式创建控件 (2)支持远程加载数据 (3)支持面板激活.远程加载事件注册 (4)支持动态添加.删除项目 实现图例 客户代码 <div> <div style="padding-left:100px; padding-bottom:12px; float:left"> <div id="accordionContainer" style="width:300px;he

我的开源框架之TAB控件

需求 (1)支持iframe.html.json格式的tab内容远程请求 (2)支持动态添加tab (3)支持远程加载完成监听,支持tab激活事件监听 (4)支持reload tab内容[如果是远程加载] (5)支持邮件菜单[未实现] 实现图例 客户代码 1 <body> 2 <div id="text"> 3 <h3>无题</h3> 4 <p>月落湖面两清影,</p> 5 <p>岸柳丝丝弄轻盈.<

我的开源框架之工具栏控件

http://www.cnblogs.com/zhaoguihua/p/redis-004.html Redis 的主从复制配置非常容易,但我们先来了解一下它的一些特性. redis 使用异步复制.从 redis 2.8 开始,slave 也会周期性的告诉 master 现在的数据量.可能只是个机制,用途应该不大. 一个 master 可以拥有多个 slave,废话,这也是业界的标配吧. slave 可以接收来自其他 slave 的连接.意思是不是就是说 slave 在接收其他的slave的连接

基于MVC+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采用EasyUI的前端界面处理技术,走MVC的技术路线,在重构完善过程中,很多细节花费不少时间进行研究和提炼,一步步走过来,也积累了不少经验,本系列将主要介绍我在进一步完善我的Web框架基础上积累的经验进行分享,本随笔主要介绍使用EasyUI的树控件构建Web界面的相关经验. 在很多界面设计上,我们可能都需要引入树列表控件,这个控件可以用zTree来实现,也

基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采用EasyUI的前端界面处理技术,走MVC的技术路线,在重构完善过程中,很多细节花费不少时间进行研究和提炼,一步步走过来,也积累了不少经验,本系列将主要介绍我在进一步完善我的Web框架基础上积累的经验进行分享,本随笔主要介绍使用EasyUI的树控件构建Web界面的相关经验. 在很多界面设计上,我们可能都需要引入树列表控件,这个控件可以用zTree来实现,也

(转)基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

http://www.cnblogs.com/wuhuacong/p/3669575.html 最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采用EasyUI的前端界面处理技术,走MVC的技术路线,在重构完善过程中,很多细节花费不少时间进行研究和提炼,一步步走过来,也积累了不少经验,本系列将主要介绍我在进一步完善我的Web框架基础上积累的经验进行分享,本随笔主要介绍使用EasyUI的树控件构建Web界面

(八)树控件(Tree Control),标签控件(tab control)

树控件 基于对话框创建工程 // 01_TreeCtrlDlg.cpp : 实现文件 // #include "stdafx.h" #include "01_TreeCtrl.h" #include "01_TreeCtrlDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg

表格树控件QtTreePropertyBrowser编译成动态库(设计师插件)

目录 一.回顾 二.动态库编译 1.命令行编译动态库和测试程序 2.vs工具编译动态库和测试程序 3.安装文档 4.测试文档 三.设计师插件编译 1.重写QDesignerCustomWidgetInterface 2.添加到插件列表 3.拷贝生成的dll 4.重启Qt Designer 四.多说一句 五.相关文章 一.回顾 上一篇文章超级实用的表格树控件--QtTreePropertyBrowser讲了怎么去编译QtTreePropertyBrowser库,并且可以简单实用.由于我下载的库是基