個人開源框架之樹控件

需求:

1.根據無限級的樹形結構的json生成樹菜單javascript

2.樹樣式能夠是圖標類型和簡單類型css

3.能夠自定義節點的圖標html

4.支持複選框java

5.支持懶加載方式請求數據node

6.支持節點點擊事件ajax

7.只有右鍵菜單【未實現】json

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 *電郵: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);
相關文章
相關標籤/搜索