我的开源框架之树控件 – hjwen

需求:

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);

 

本文链接:我的开源框架之树控件,转载请注明。



You must enable javascript to see captcha here!

Copyright © All Rights Reserved · Green Hope Theme by Sivan & schiy · Proudly powered by WordPress

无觅相关文章插件,快速提升流量