在网页中经常要用到显示拥有层级关系的数据,比如信息发布网站的栏目菜单、某单位的组织结构等等。对于这类数据一般采用树形结构来显示,这样结构清晰明了,操作方便。在asp.net中有TreeView的组件,它的功能已经比较强大。但往往针对不同的项目的时候,他的扩展性,维护性个人感觉不太好。所以在自己写了一个基于jquery 的树js组件,事实完全可以抛离jquery用javascript就行,自己还是懒了点。
这个组件只能以异步的方式加载数据,自己没有写同步的。感觉同步加载数据的用处不是很大,不如一步到位直接写成异部的。组件是没有层级限制的。浏览器的兼容性自己只在IE10和Chrome 23中进行了测试,这里只想与大家分享设计的思路,至于真正的实用性,我自己的代码能力有限,其实不能得到什么很广泛的应用。
基本的HTML代码如下:
1 <div class="div_item" spath="1.1"> 2 <ul id="b7b16a42-060d-4395-b7db-6cc1434513e3" class="ul_item"> 3 <li class="ltr_expanded"></li> 4 <li class="lim_expanded"></li> 5 <li class="lte">黑龙江省</li> 6 </ul> 7 </div>
这是tree中的一个单元,用ul元素 显示了该单元中整行的结构内容。如果添加子节点,只需要在<div class="div_item" spath="1.1">元素后面追加一个DIV元素即可,控制好DIV的左侧距离既可以清晰的显示属性结构。代码整体很简单,没什么好说的,直接贴出供大家参考:
treeSJ01.js
1 /*! 2 * 基于Jquery 的Tree插件 3 * 只可以异步加载数据 4 * 三角号箭头展开图标 5 * Author:Jann 6 * Date: 2012-11-15 7 */ 8 $.fn.Tree = function (settings) { 9 var dfop = { 10 method: "POST", 11 datatype: "JSON", 12 url: "", 13 paramValue: "", 14 redirectListUrl: "", 15 redirectEditUrlB: "" 16 } 17 $.extend(dfop, settings); 18 var me = $(this); 19 var id = me.attr("id"); 20 if (id == null || id == "") { 21 id = "bbtree" + new Date().getTime(); 22 me.attr("id", id); 23 } 24 buildTreeNode(me, 1, dfop.paramValue); 25 function buildTreeNode(objDiv, spath, parentID) { 26 objDiv.after("<div id='tree_div_wait'></div>"); 27 asyncLoadNodeData(parentID, function (result) { 28 if (result.length > 0) { 29 nodeBuild(objDiv, result, spath); 30 } 31 }); 32 } 33 function nodeBuild(objectDiv, nodes, spath) { 34 var html = []; 35 var nodeLen = 0; 36 if (spath != 1) { 37 nodeLen = spath.split('.').length - 1; 38 } 39 html.push("<div style='clear:both;margin-left: 20px;'>"); 40 for (var i = 0; i < nodes.length; i++) { 41 if (i == nodes.length - 1) { 42 slast = 1; 43 } 44 html.push("<div class='div_item' spath='" + spath + "." + (i + 1) + "'>"); 45 html.push("<ul id='" + nodes[i].TreeID + "' class='ul_item'>"); 46 if (nodes[i].HasChild == 1) { 47 html.push("<li class='ltr_collapsed'></li>"); 48 } 49 else { 50 html.push("<li class='ltr_none'></li>"); 51 } 52 html.push("<li class='lim_collapsed'></li>"); 53 html.push("<li class='lte'>" + nodes[i].Name + "</li>"); 54 html.push("</ul>"); 55 html.push("</div>"); 56 } 57 html.push("</div>"); 58 $("#tree_div_wait").remove(); 59 objectDiv.after(html.join("")); 60 for (var j = 0; j < nodes.length; j++) { 61 $("div[spath='" + spath + "." + (j + 1) + "'] li:first:not([class='ltr_none'])") 62 .mouseenter(triangleME) 63 .mouseleave(triangleML) 64 .click(nodeClick); 65 } 66 } 67 function asyncLoadNodeData(parentID, callback) { 68 var _data = { parentid: parentID }; 69 $.ajax({ 70 type: dfop.method, 71 url: dfop.url, 72 data: _data, 73 dataType: dfop.datatype, 74 success: callback, 75 error: function (e) { 76 alert("load data error!"); 77 } 78 }); 79 } 80 function nodeClick(e) { 81 var itemContainer = $(this).parent().parent(); 82 var spath = itemContainer.attr("spath"); 83 var targetLI = e.target || e.srcElement; 84 switch (targetLI.className) { 85 case "ltr_collapsed_B": 86 $(this).removeClass("ltr_collapsed_B").addClass("ltr_expanded_B"); 87 if ($("div[spath='" + spath + ".1']").length == 0) { 88 buildTreeNode(itemContainer, spath, $(this).parent().attr("id")); 89 } 90 else { 91 $("div[spath='" + spath + ".1']").parent().css("display", "block"); 92 } 93 $(this).next().removeClass("lim_collapsed").addClass("lim_expanded"); 94 break; 95 case "ltr_expanded_B": 96 $(this).removeClass("ltr_expanded_B").addClass("ltr_collapsed_B"); 97 $("div[spath='" + spath + ".1']").parent().css("display", "none"); 98 $(this).next().removeClass("lim_expanded").addClass("lim_collapsed"); 99 break; 100 } 101 } 102 function triangleME() { 103 var className = $(this).attr("class"); 104 var newClassName = className + "_B"; 105 $(this).removeClass(className).addClass(newClassName); 106 } 107 function triangleML() { 108 var className = $(this).attr("class"); 109 var newClassName = className.replace('_B', ''); 110 $(this).removeClass(className).addClass(newClassName); 111 } 112 }
TreeSJ.css
1 body { font-size: 12px; } 2 .ul_item { clear: both; margin: 0px; padding: 0px; } 3 .ul_item li { list-style-type: none; float: left; height: 22px; display: block; line-height: 22px; background-position: center center; background-repeat: no-repeat;} 4 .ul_item li.ltr_collapsed { 20px; background-image: url('images/itemCollapsedIcon.png'); } 5 .ul_item li.ltr_collapsed_B { 20px; background-image: url('images/itemCollapsedIconB.png'); } 6 .ul_item li.ltr_expanded { 20px; background-image: url('images/itemExpandedIcon.png'); } 7 .ul_item li.ltr_expanded_B { 20px; background-image: url('images/itemExpandedIconB.png'); } 8 .ul_item li.ltr_none { 20px; background-image: url(''); } 9 .ul_item li.lim_collapsed { 20px; background-image: url('images/ext_n.png'); } 10 .ul_item li.lim_expanded { 20px; background-image: url('images/ext_y.png'); } 11 .ul_item li.lte { line-height: 25px; } 12 .div_item { float: left; clear: both; } 13 #tree_div_wait 14 { 15 height: 22px; 16 float: left; 17 clear: both; 18 22px; 19 background-position: center center; 20 background-image: url('images/tree-wait.gif'); 21 background-repeat: no-repeat; 22 margin-left:20px; 23 }
前台调用:
1 <html> 2 <head> 3 <meta name="viewport" content="width=device-width" /> 4 <title>TreePage</title> 5 <script src="~/Scripts/jquery-1.7.1.js"></script> 6 <script src="~/Scripts/tree/treeSJ01.js"></script> 7 <link href="~/Content/TreeSJ.css" rel="stylesheet" /> 8 <script> 9 $().ready(function () { 10 $("#treediv").Tree({ 11 'url': '@Url.Action("GetData")', 12 'paramValue':'00000000-0000-0000-0000-000000000000' 13 }); 14 }); 15 </script> 16 17 </head> 18 <body> 19 <div id="treediv"> 20 </div> 21 </body> 22 </html>
json 数据结构
1 public class Tree 2 { 3 public Guid TreeID { set; get; } 4 public string Name { set; get; } 5 public Guid ParentID { set; get; } 6 public string Url { set; get; } 7 public int HasChild { set; get; } 8 }
总结:自己以前写了一个带网格线、加好图标的Tree但是代码很罗嗦,所以又写了一个三角号标的。代码中有一个地方大家需要注意,就是在读取数据的时候用数据参数,自己写死为parentid,这样如果是不同的参数,就需要将treeSJ01.js文件中的参数名手动更改,我自己还没有找到很好的解决方法。