Home  >  Article  >  Web Front-end  >  Create a high-performance TreeView (asp.net) based on jQuery_jquery

Create a high-performance TreeView (asp.net) based on jQuery_jquery

WBOY
WBOYOriginal
2016-05-16 18:10:24938browse

According to my project practice, there are several key points:

1: Support static tree, that is, load all data to the client at one time.
2: Asynchronous tree, that is, only one or several levels of nodes are loaded at a time, and child nodes can load data asynchronously.
3: Checkbox tree (may be a static tree or an asynchronous tree), used for selection (such as selecting an organization, selecting data dictionary items), etc. It is best to support node cascading (this is the difficulty)
4: Able to carry large amounts of data and perform well
5: Able to run well in mainstream browsers

Then the TreeView I want to build is to achieve these 5 main indicators.

Let’s take a look at the renderings first

image

The above picture is the data tree of China's administrative regions, with a total of 3500 nodes.

Then we are going to start work;

1: The first determined node Dom structure (that is, what kind of HTML is used to build the node)

  • The more common one is the table within the table (the style is easy to control, but with large amounts of data and deep-layered trees, this structure will definitely not be able to withstand it)
  • There is also a relatively new method of UL covering LI. This is the method adopted by many books nowadays. For example, Jquery.treeview adopts this format. The advantage is that the structure is simple and clear.
    And it is not supported when Js browsers can also display the shape of a tree (this situation can actually be ignored), but the nodes of Jquery.treeview cannot be opened by internal elements under IE, especially IE6 (IE7 and 8). cannot be opened when it reaches a certain depth), please have a strange phenomenon (I guess it is because padding is used for indentation, margin-left: negative value to control the icon position, but it is also difficult to modify), in this case This problem occurs when the book is deformed (Jquery.treeview), which can only be solved by setting the width of the node.

image

Node structure of JQuery.treeview

image

Jquery.TreeView Under IE6, the third level will be misaligned

image Expand to level 5 under IE8

  • There are also some methods of div nesting tables. CSDN’s navigation tree is like this. It is a compromise method (the nodes are not too complicated, and the CSS is easier to write), as shown in the figure below
    image

I also used the second method, but the indentation was filled in the blanks, that is, the indented position was filled with blank images to avoid the problem of Jquery.treeview

image

My tree node structure

After determining the HTML of the node, we can write CSS. With the renderings, there is a node structure and then the CSS is written

The following is the complete code of CSS

Copy the code The code is as follows:

.ie .bbit-tree .bbit-tree-bwrap{
}
.bbit-tree ul,.bbit-tree li
{
list-style-type:none;
margin:0px;
padding:0px;
}
.bbit-tree-body
{
font-size:12px;
}
.bbit-tree-icon, .bbit-tree-ec-icon, .bbit-tree-node-cb,.bbit-tree-elbow-line, .bbit-tree-elbow, .bbit-tree-elbow-end, .bbit-tree-elbow-plus, .bbit-tree-elbow-minus, .bbit-tree-elbow-end-plus, .bbit-tree-elbow-end-minus{
border: 0 none;
height: 18px;
margin: 0;
padding: 0;
vertical-align: top;
width: 16px;
background-repeat: no-repeat;
}
.bbit-tree-node-cb
{
height:16px;
}
.bbit-tree-node-collapsed .bbit-tree-node-icon, .bbit-tree-node-expanded .bbit-tree-node-icon, .bbit-tree-node-leaf .bbit-tree-node-icon{
border: 0 none;
height: 18px;
margin: 0;
padding: 0;
vertical-align: top;
width: 16px;
background-position:center;
background-repeat: no-repeat;
}
.ie .bbit-tree-node-indent img, .ie .bbit-tree-node-icon, .ie .bbit-tree-ec-icon {
vertical-align:middle !important;
}
.bbit-tree-noicon .bbit-tree-node-icon{
width:0; height:0;
}
/* No line styles 没有线的样式 */
.bbit-tree-no-lines .bbit-tree-elbow{
background:transparent;
}
.bbit-tree-no-lines .bbit-tree-elbow-end{
background:transparent;
}
.bbit-tree-no-lines .bbit-tree-elbow-line{
background:transparent;
}
/* Arrows Vista系统树的样式只有箭头*/
.bbit-tree-arrows .bbit-tree-elbow{
background:transparent;
}
.bbit-tree-arrows .bbit-tree-elbow-plus{
background:transparent no-repeat 0 0;
}
.bbit-tree-arrows .bbit-tree-elbow-minus{
background:transparent no-repeat -16px 0;
}
.bbit-tree-arrows .bbit-tree-elbow-end{
background:transparent;
}
.bbit-tree-arrows .bbit-tree-elbow-end-plus{
background:transparent no-repeat 0 0;
}
.bbit-tree-arrows .bbit-tree-elbow-end-minus{
background:transparent no-repeat -16px 0;
}
.bbit-tree-arrows .bbit-tree-elbow-line{
background:transparent;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-plus{
background-position:-32px 0;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-minus{
background-position:-48px 0;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-end-plus{
background-position:-32px 0;
}
.bbit-tree-arrows .bbit-tree-ec-over .bbit-tree-elbow-end-minus{
background-position:-48px 0;
}
.bbit-tree-elbow-plus, .bbit-tree-elbow-minus, .bbit-tree-elbow-end-plus, .bbit-tree-elbow-end-minus{
cursor:pointer;
}
.ie ul.bbit-tree-node-ct{
font-size:0;
line-height:0;
zoom:1;
}
.bbit-tree-node{
white-space: nowrap;
}
.bbit-tree-node-el {
line-height:18px;
cursor:default;
/* cursor:pointer;*/
}
.bbit-tree-node a{
text-decoration:none;
-khtml-user-select:none;
-moz-user-select:none;
-webkit-user-select:ignore;
-kthml-user-focus:normal;
-moz-user-focus:normal;
-moz-outline: 0 none;
outline:0 none;
}
.bbit-tree-node a span{
text-decoration:none;
padding:1px 3px 1px 2px;
}
.bbit-tree-node .bbit-tree-node-disabled .bbit-tree-node-icon{
-moz-opacity: 0.5;
opacity:.5;
filter: alpha(opacity=50);
}
.bbit-tree-node .bbit-tree-node-inline-icon{
background:transparent;
}
.bbit-tree-node a:hover{
text-decoration:none;
}

/* Fix for ie rootVisible:false issue,修正一个IEdebug */
.bbit-tree-root {
zoom:1;
}

/***********Here is the icon, you can replace it here*******************/
.bbit-tree-node-expanded .bbit-tree-node-icon{
background-image:url(images/tree/folder-open.gif);
}
.bbit-tree-node-leaf .bbit-tree-node-icon{
background-image:url(images/tree/leaf.gif);
}
.bbit-tree-node-collapsed .bbit-tree-node-icon{
background-image:url(images/tree/folder.gif);
}
.bbit-tree-node-loading .bbit-tree-node-icon{
background-image:url(images/tree/loading.gif) !important;
}
.bbit-tree-node .bbit-tree-node-inline-icon {
background-image: none;
}
.bbit-tree-node-loading a span{
font-style: italic;
color:#444444;
}
.bbit-tree-lines .bbit-tree-elbow{
background-image:url(images/tree/elbow.gif);
}
.bbit-tree-lines .bbit-tree-elbow-plus{
background-image:url(images/tree/elbow-plus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-minus{
background-image:url(images/tree/elbow-minus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end{
background-image:url(images/tree/elbow-end.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end-plus{
background-image:url(images/tree/elbow-end-plus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-end-minus{
background-image:url(images/tree/elbow-end-minus.gif);
}
.bbit-tree-lines .bbit-tree-elbow-line{
background-image:url(images/tree/elbow-line.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-plus{
background-image:url(images/tree/elbow-plus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-minus{
background-image:url(images/tree/elbow-minus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-end-plus{
background-image:url(images/tree/elbow-end-plus-nl.gif);
}
.bbit-tree-no-lines .bbit-tree-elbow-end-minus{
background-image:url(images/tree/elbow-end-minus-nl.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-plus{
background-image:url(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-minus{
background-image:url(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-end-plus{
background-image:url(images/tree/arrows.gif);
}
.bbit-tree-arrows .bbit-tree-elbow-end-minus{
background-image:url(images/tree/arrows.gif);
}
/*TreeNode 选中的Disabled的一些颜色,字体样式*/
.bbit-tree-node{
color:#000;
font: normal 11px arial, tahoma, helvetica, sans-serif;
}
.bbit-tree-node a{
color:#000;
}
.bbit-tree-node a span{
color:#000;
}
.bbit-tree-node .bbit-tree-node-disabled a span{
color:gray !important;
}
.bbit-tree-node .bbit-tree-node-over {
background-color: #eee;
}
.bbit-tree-node .bbit-tree-selected {
background-color: #d9e8fb;
}

上面了树的基本样式外,定义了一个有+号带line的样式和+号不带line的样式

image 这就是那个+号带line的样式

css中所用到的所有图片

arrows elbow elbow-end elbow-end-minus elbow-end-minus-nl elbow-end-plus elbow-end-plus-nl elbow-line elbow-minus elbow-minus-nl elbow-plus elbow-plus-nl folder folder-open leaf loading

checkbox_2 checkbox_0 checkbox_1

2: Determine the data structure

Copy the code The code is as follows:

var menudata = [{
id: "0.1", // A unique ID is enough
text: "Beyondbit UI Demo",
hasChildren: true,
isexpand: true,
complete: true,
ChildNodes: [{
id: "0.1.1",
text: "Date selection",
hasChildren: true,
isexpand: false,
complete: true,
ChildNodes: [{
id: "0.1.1.1",
text: "Control Demo",
value: "Testpages/datepickerDemo.htm",
hasChildren: false,
isexpand: false,
complete: true,
ChildNodes: null
},
...
]

Such a structure is The first advantage is that the data itself is hierarchical, which is very convenient for traversal. You will see it in the subsequent cascading associations
3: Once the face is done, start making the lining and writing scripts (Javascript)
I am JQuery has gained supporters, so naturally the js framework uses Jquery
First upload the complete code, and then analyze it one by one
Copy the code The code is as follows:

/****************************************
author:xuanye.wan@gmail.com
page:http://xuanye.cnblogs.com/
***************************************/
(function($) {
$.fn.swapClass = function(c1, c2) {
return this.removeClass(c1).addClass(c2);
}
$.fn.switchClass = function(c1, c2) {
if (this.hasClass(c1)) {
return this.swapClass(c1, c2);
}
else {
return this.swapClass(c2, c1);
}
}
$.fn.treeview = function(settings) {
var dfop =
{
method: "POST",
datatype: "json",
url: false,
cbiconpath: "/images/icons/",
icons: ["checkbox_0.gif", "checkbox_1.gif", "checkbox_2.gif"],
showcheck: false, //是否显示选择
oncheckboxclick: false, //当checkstate状态变化时所触发的事件,但是不会触发因级联选择而引起的变化
onnodeclick: false,
cascadecheck: true,
data: null,
clicktoggle: true, //点击节点展开和收缩子节点
theme: "bbit-tree-arrows" //bbit-tree-lines ,bbit-tree-no-lines,bbit-tree-arrows
}
$.extend(dfop, settings);
var treenodes = dfop.data;
var me = $(this);
var id = me.attr("id");
if (id == null || id == "") {
id = "bbtree" + new Date().getTime();
me.attr("id", id);
}
var html = [];
buildtree(dfop.data, html);
me.addClass("bbit-tree").html(html.join(""));
InitEvent(me);
html = null;
//预加载图片
if (dfop.showcheck) {
for (var i = 0; i < 3; i++) {
var im = new Image(16,16);
im.src = dfop.cbiconpath + dfop.icons[i];
}
}
//region
function buildtree(data, ht) {
ht.push("
"); // Wrap ;
ht.push("
"); // body ;
ht.push("
    "); //root
    var l = data.length;
    for (var i = 0; i < l; i++) {
    buildnode(data[i], ht, 0, i, i == l - 1);
    }
    ht.push("
"); // root and;
ht.push("
"); // body end;
ht.push("
"); // Wrap end;
}
//endregion
function buildnode(nd, ht, deep, path, isend) {
ht.push("
  • ");
    ht.push("
    var cs = [];
    cs.push("bbit-tree-node-el");
    if (nd.hasChildren) {
    cs.push(nd.isexpand ? "bbit-tree-node-expanded" : "bbit-tree-node-collapsed");
    }
    else {
    cs.push("bbit-tree-node-leaf");
    }
    if (nd.classes) { cs.push(nd.classes); }
    ht.push(" class='", cs.join(" "), "'>");
    //span indent
    ht.push("");
    if (deep == 1) {
    ht.push("");
    }
    else if (deep > 1) {
    ht.push("");
    for (var j = 1; j < deep; j++) {
    ht.push("");
    }
    }
    ht.push("
    ");
    //img
    cs.length = 0;
    if (nd.hasChildren) {
    if (nd.isexpand) {
    cs.push(isend ? "bbit-tree-elbow-end-minus" : "bbit-tree-elbow-minus");
    }
    else {
    cs.push(isend ? "bbit-tree-elbow-end-plus" : "bbit-tree-elbow-plus");
    }
    }
    else {
    cs.push(isend ? "bbit-tree-elbow-end" : "bbit-tree-elbow");
    }
    ht.push("");
    ht.push("");
    //checkbox
    if (dfop.showcheck && nd.showcheck) {
    if (nd.checkstate == null || nd.checkstate == undefined) {
    nd.checkstate = 0;
    }
    ht.push("");
    }
    //a
    ht.push("");
    ht.push("", nd.text, "");
    ht.push("
    ");
    ht.push("
    ");
    //Child
    if (nd.hasChildren) {
    if (nd.isexpand) {
    ht.push("
      ");
      if (nd.ChildNodes) {
      var l = nd.ChildNodes.length;
      for (var k = 0; k < l; k ) {
      nd.ChildNodes[k].parent = nd;
      buildnode(nd.ChildNodes[k], ht, deep 1, path "." k, k == l - 1);
      }
      }
      ht.push("
    ");
    }
    else {
    ht.push("
      ");
      }
      }
      ht.push("
    • ");
      nd.render = true;
      }
      function getItem(path) {
      var ap = path.split(".");
      var t = treenodes;
      for (var i = 0; i < ap.length; i ) {
      if (i == 0) {
      t = t[ap[i]];
      }
      else {
      t = t.ChildNodes[ap[i]];
      }
      }
      return t;
      }
      function check(item, state, type) {
      var pstate = item.checkstate;
      if (type == 1) {
      item.checkstate = state;
      }
      else {// 上溯
      var cs = item.ChildNodes;
      var l = cs.length;
      var ch = true;
      for (var i = 0; i < l; i ) {
      if ((state == 1 && cs[i].checkstate != 1) || state == 0 && cs[i].checkstate != 0) {
      ch = false;
      break;
      }
      }
      if (ch) {
      item.checkstate = state;
      }
      else {
      item.checkstate = 2;
      }
      }
      //change show
      if (item.render && pstate != item.checkstate) {
      var et = $("#" id "_" item.id "_cb");
      if (et.length == 1) {
      et.attr("src", dfop.cbiconpath dfop.icons[item.checkstate]);
      }
      }
      }
      //遍历子节点
      function cascade(fn, item, args) {
      if (fn(item, args, 1) != false) {
      if (item.ChildNodes != null && item.ChildNodes.length > 0) {
      var cs = item.ChildNodes;
      for (var i = 0, len = cs.length; i < len; i ) {
      cascade(fn, cs[i], args);
      }
      }
      }
      }
      //冒泡的祖先
      function bubble(fn, item, args) {
      var p = item.parent;
      while (p) {
      if (fn(p, args, 0) === false) {
      break;
      }
      p = p.parent;
      }
      }
      function nodeclick(e) {
      var path = $(this).attr("tpath");
      var et = e.target || e.srcElement;
      var item = getItem(path);
      //debugger;
      if (et.tagName == "IMG") {
      // 号需要展开
      if ($(et).hasClass("bbit-tree-elbow-plus") || $(et).hasClass("bbit-tree-elbow-end-plus")) {
      var ul = $(this).next(); //"bbit-tree-node-ct"
      if (ul.hasClass("bbit-tree-node-ct")) {
      ul.show();
      }
      else {
      var deep = path.split(".").length;
      if (item.complete) {
      item.ChildNodes != null && asnybuild(item.ChildNodes, deep, path, ul, item);
      }
      else {
      $(this).addClass("bbit-tree-node-loading");
      asnyloadc(ul, item, function(data) {
      item.complete = true;
      item.ChildNodes = data;
      asnybuild(data, deep, path, ul, item);
      });
      }
      }
      if ($(et).hasClass("bbit-tree-elbow-plus")) {
      $(et).swapClass("bbit-tree-elbow-plus", "bbit-tree-elbow-minus");
      }
      else {
      $(et).swapClass("bbit-tree-elbow-end-plus", "bbit-tree-elbow-end-minus");
      }
      $(this).swapClass("bbit-tree-node-collapsed", "bbit-tree-node-expanded");
      }
      else if ($(et).hasClass("bbit-tree-elbow-minus") || $(et).hasClass("bbit-tree-elbow-end-minus")) { //- 号需要收缩
      $(this).next().hide();
      if ($(et).hasClass("bbit-tree-elbow-minus")) {
      $(et).swapClass("bbit-tree-elbow-minus", "bbit-tree-elbow-plus");
      }
      else {
      $(et).swapClass("bbit-tree-elbow-end-minus", "bbit-tree-elbow-end-plus");
      }
      $(this).swapClass("bbit-tree-node-expanded", "bbit-tree-node-collapsed");
      }
      else if ($(et).hasClass("bbit-tree-node-cb")) // 点击了Checkbox
      {
      var s = item.checkstate != 1 ? 1 : 0;
      var r = true;
      if (dfop.oncheckboxclick) {
      r = dfop.oncheckboxclick.call(et, item, s);
      }
      if (r != false) {
      if (dfop.cascadecheck) {
      //遍历
      cascade(check, item, s);
      //上溯
      bubble(check, item, s);
      }
      else {
      check(item, s, 1);
      }
      }
      }
      }
      else {
      if (dfop.citem) {
      $("#" id "_" dfop.citem.id).removeClass("bbit-tree-selected");
      }
      dfop.citem = item;
      $(this).addClass("bbit-tree-selected");
      if (dfop.onnodeclick) {
      dfop.onnodeclick.call(this, item);
      }
      }
      }
      function asnybuild(nodes, deep, path, ul, pnode) {
      var l = nodes.length;
      if (l > 0) {
      var ht = [];
      for (var i = 0; i < l; i ) {
      nodes[i].parent = pnode;
      buildnode(nodes[i], ht, deep, path "." i, i == l - 1);
      }
      ul.html(ht.join(""));
      ht = null;
      InitEvent(ul);
      }
      ul.addClass("bbit-tree-node-ct").css({ "z-index": 0, position: "static", visibility: "visible", top: "auto", left: "auto", display: "" });
      ul.prev().removeClass("bbit-tree-node-loading");
      }
      function asnyloadc(pul, pnode, callback) {
      if (dfop.url) {
      var param = builparam(pnode);
      $.ajax({
      type: dfop.method,
      url: dfop.url,
      data: param,
      dataType: dfop.datatype,
      success: callback,
      error: function(e) { alert("error occur!"); }
      });
      }
      }
      function builparam(node) {
      var p = [{ name: "id", value: encodeURIComponent(node.id) }
      , { name: "text", value: encodeURIComponent(node.text) }
      , { name: "value", value: encodeURIComponent(node.value) }
      , { name: "checkstate", value: node.checkstate}];
      return p;
      }
      function InitEvent(parent) {
      var nodes = $("li.bbit-tree-node>div", parent);
      nodes.each(function(e) {
      $(this).hover(function() {
      $(this).addClass("bbit-tree-node-over");
      }, function() {
      $(this).removeClass("bbit-tree-node-over");
      })
      .click(nodeclick)
      .find("img.bbit-tree-ec-icon").each(function(e) {
      if (!$(this).hasClass("bbit-tree-elbow")) {
      $(this).hover(function() {
      $(this).parent().addClass("bbit-tree-ec-over");
      }, function() {
      $(this).parent().removeClass("bbit-tree-ec-over");
      });
      }
      });
      });
      }
      function getck(items, c, fn) {
      for (var i = 0, l = items.length; i < l; i ) {
      items[i].checkstate == 1 && c.push(fn(items[i]));
      if (items[i].ChildNodes != null && items[i].ChildNodes.length > 0) {
      getck(items[i].ChildNodes, c, fn);
      }
      }
      }
      me[0].t = {
      getSelectedNodes: function() {
      var s = [];
      getck(treenodes, s, function(item) { return item });
      return s;
      },
      getSelectedValues: function() {
      var s = [];
      getck(treenodes, s, function(item) { return item.value });
      return s;
      },
      getCurrentItem: function() {
      return dfop.citem;
      }
      };
      return me;
      }
      //获取所有选中的节点的Value数组
      $.fn.getTSVs = function() {
      if (this[0].t) {
      return this[0].t.getSelectedValues();
      }
      return null;
      }
      //获取所有选中的节点的Item数组
      $.fn.getTSNs = function() {
      if (this[0].t) {
      return this[0].t.getSelectedNodes();
      }
      return null;
      }
      $.fn.getTCT = function() {
      if (this[0].t) {
      return this[0].t.getCurrentItem();
      }
      return null;
      }
      })(jQuery);

      第一步:自然是所有Jquery的控件的第一步都是搭这个架子,兼容JQuery和$避免闭包,避免和其他类库冲突,接受一个参数(是个对象)
      复制代码 代码如下:

      ;(function($) {
      //也可以使用$.fn.extend(treeview:function(setting){})
      $.fn.treeview = function(settings) {
      }
      })(jQuery);

      那第二步:给控件加一些参数默认参数,同时能调用方法$.extend让最终调用时的参数覆盖默认的(如果没有则使用默认)
      复制代码 代码如下:

      var dfop ={
      method: "POST",//默认采用POST提交数据
      datatype: "json",//数据类型是json
      url: false,//异步请求的url
      cbiconpath: "/images/icons/",//checkbox icon的目录位置
      icons: ["checkbox_0.gif", "checkbox_1.gif", "checkbox_2.gif"],//checkbxo三态的图片
      showcheck: false, //是否显示checkbox
      oncheckboxclick: false, //点击checkbox时触发的事件
      onnodeclick: false,//点击node触发的时间
      cascadecheck: true,//是否启用级联
      data: null,//初始化数据
      theme: "bbit-tree-arrows" //三种风格备选bbit-tree-lines ,bbit-tree-no-lines,bbit-tree-arrows
      }
      //用传进来的参数覆盖默认,没传则保留
      $.extend(dfop, settings);

      第三步:生成默认数据的HTML(根据我们的分析节点的Dom结构,数据的数据结构,生成节点那是非常的简单),,添加到当前容器中。最后是注册事件这里有一个非常重要的地方,即懒加载(没有展开的节点HTML是不生成的),这就要求我们在树内部要维护一套数据(开销很小),对于性能的提升那是相当的明显。另外一个重要的地方,就是使用一次生成所有展开节点的HTML并通过innerHTML属性来生成Dom,而不是通过append操作,因为直接操作innerHTML比通过dom原生的方法要快上N倍(节点越多,N越大),切记切记!
      复制代码 代码如下:

      var treenodes = dfop.data; //For internal data, you can actually use dfop.data directly
      var me = $(this);
      var id = me.attr("id ");
      if (id == null || id == "") {
      id = "bbtree" new Date().getTime();
      me.attr("id", id );
      }//Globally unique ID
      var html = [];
      buildtree(dfop.data, html);//Generate the HTML of the expanded node and push it into the array
      me. addClass("bbit-tree").html(html.join(""));
      InitEvent(me);//Initialization event
      html = null;

      at node During the generation process, the Path of the node can be generated at the same time for easy retrieval
      Copy the code The code is as follows:

      if (nd.hasChildren) { //There is a child node
      if (nd.isexpand) {//At the same time, if the node has been expanded, the child node will be output
      ht.push("
        ");
        if (nd.ChildNodes) {
        var l = nd.ChildNodes.length;
        for (var k = 0; k < l; k ) {//Recursively call and produce the path of the node
        nd.ChildNodes[k].parent = nd;
        buildnode(nd.ChildNodes[k], ht, deep 1, path "." k, k == l - 1);
        }
        }
        ht.push("
      ");
      }
      else { //Otherwise it is in the pending output state
      ht.push("
        ");
        }
        }

        Register the event and accept the parameter parent, that is, attach the event from a certain parent node (because of the hover effect, the event is in each On the node, if the effect is cancelled, the event can be directly attached to the Tree and distributed through the Event's srcElement, which can slightly improve performance)
        Copy code The code is as follows:

        function InitEvent(parent) {
        var nodes = $("li.bbit-tree-node>div", parent);
        nodes.each(function (e) {
        $(this).hover(function() {
        $(this).addClass("bbit-tree-node-over"); //Style changes of mouse floating nodes
        }, function() {
        $(this).removeClass("bbit-tree-node-over");
        })
        .click(nodeclick)//node’s onclick event, this is the key point Oh
        .find("img.bbit-tree-ec-icon").each(function(e) { //arrow's hover event, in order to realize the vista style
        if (!$(this) .hasClass("bbit-tree-elbow")) {
        $(this).hover(function() {
        $(this).parent().addClass("bbit-tree-ec-over" );
        }, function() {
        $(this).parent().removeClass("bbit-tree-ec-over");
        });
        }
        } );
        });
        }

        The most important thing here is the click event of the node, because it has to deal with many things, such as the expansion and contraction of the tree (if the child node does not exist , but hasChildren is true, and the complete attribute is not true, the child node needs to be loaded asynchronously. If the child node exists, but there is no Render, then Render is required). Clicking the checkbox will trigger the cascade event and oncheckbox event. Clicking other will trigger the configuration. Conditional nodeonclick event, all of which distinguish the clicked object through the class of the source element of the previous event
        Copy the code The code is as follows:

        function nodeclick(e) {
        var path = $(this).attr("tpath");//Get the node path
        var et = e.target || e.srcElement; //Get event source
        var item = getItem(path);//Get node data based on path
        //debugger;
        if (et.tagName == "IMG") {
        / The / sign needs to be expanded and the plus and minus signs are processed
        if ($(et).hasClass("bbit-tree-elbow-plus") || $(et).hasClass("bbit-tree-elbow-end-plus ")) {
        var ul = $(this).next(); //"bbit-tree-node-ct"
        if (ul.hasClass("bbit-tree-node-ct")) {
        ul.show();
        }
        else {
        var deep = path.split(".").length;
        if (item.complete) {
        item .ChildNodes != null && asnybuild(item.ChildNodes, deep, path, ul, item);
        }
        else {
        $(this).addClass("bbit-tree-node-loading") ;
        asnyloadc(ul, item, function(data) {
        item.complete = true;
        item.ChildNodes = data;
        asnybuild(data, deep, path, ul, item);
        });
        }
        }
        if ($(et).hasClass("bbit-tree-elbow-plus")) {
        $(et).swapClass("bbit- tree-elbow-plus", "bbit-tree-elbow-minus");
        }
        else {
        $(et).swapClass("bbit-tree-elbow-end-plus", " bbit-tree-elbow-end-minus");
        }
        $(this).swapClass("bbit-tree-node-collapsed", "bbit-tree-node-expanded");
        }
        else if ($(et).hasClass("bbit-tree-elbow-minus") || $(et).hasClass("bbit-tree-elbow-end-minus")) { //- The number needs to be shrunk
        $(this).next().hide();
        if ($(et).hasClass("bbit-tree-elbow-minus")) {
        $(et) .swapClass("bbit-tree-elbow-minus", "bbit-tree-elbow-plus");
        }
        else {
        $(et).swapClass("bbit-tree-elbow- end-minus", "bbit-tree-elbow-end-plus");
        }
        $(this).swapClass("bbit-tree-node-expanded", "bbit-tree-node-collapsed ");
        }
        else if ($(et).hasClass("bbit-tree-node-cb")) // Checkbox is clicked
        {
        var s = item.checkstate ! = 1 ? 1 : 0;
        var r = true;
        if (dfop.oncheckboxclick) { //Trigger the configured function
        r = dfop.oncheckboxclick.call(et, item, s);
        }
        if (r != false) {//If the return value is not false, that is, the checkbxo change is valid
        if (dfop.cascadecheck) {//Allow triggering of cascade
        //Traversal
        cascade(check, item, s);//Associate downwards
        //Associate up
        bubble(check, item, s); //Associate upwards
        }
        else {
        check(item, s, 1);//Otherwise just keep to yourself
        }
        }
        }
        }
        else {//Clicked elsewhere
        if (dfop.citem ) { //Previous current node
        $("#" id "_" dfop.citem.id).removeClass("bbit-tree-selected");
        }
        dfop.citem = item ;//The current node this time
        $(this).addClass("bbit-tree-selected");
        if (dfop.onnodeclick) {
        dfop.onnodeclick.call(this, item) ;
        }
        }
        }

        Expand the node. Part of the code for the asynchronous request should not be very complicated, so I won’t go into details. The key point is to talk about the cascade
        level There are two problems to deal with. The first is to traverse the child nodes, and the second is to trace back to the ancestor node. Because of our data structure, both operations are very simple
        Copy code The code is as follows:

        //Traverse child nodes
        function cascade(fn, item, args) {
        if (fn (item, args, 1) != false) {
        if (item.ChildNodes != null && item.ChildNodes.length > 0) {
        var cs = item.ChildNodes;
        for (var i = 0, len = cs.length; i < len; i ) {
        cascade(fn, cs[i], args);
        }
        }
        }
        }
        //Bubble ancestor
        function bubble(fn, item, args) {
        var p = item.parent;
        while (p) {
        if (fn(p, args, 0) === false) {
        break;
        }
        p = p.parent;
        }
        }

        check will be triggered when a node is found This callback function is used to determine the status of the current node. Please see the comments in the code below for details. It should be clearer and describes the process
        Copy code The code is as follows:

        function check(item, state, type) {
        var pstate = item.checkstate; //현재 상태
        if (type == 1) {
        item.checkstate = state; //하위 노드를 순회하는 경우 하위 노드는 상위 노드가 됩니다.
        }
        else {// 역추적, 이는 좀 더 복잡합니다.
        var cs = item.ChildNodes //모두 가져오기 현재 노드의 자식 Node
        var l = cs.length;
        var ch = true //중간 상태가 아닌지 여부
        for (var i = 0; i < l; i ) {
        if ( (state == 1 && cs[i].checkstate != 1) || state == 0 && cs[i].checkstate != 0) {
        ch = false ;
        break;//his 하위 노드 중 하나가 선택되지 않는 한 절반만 선택됩니다.
        }
        }
        if (ch) {
        item.checkstate = state; // 절반 선택되지 않은 경우 하위 노드는 무엇입니까?
        }
        else {
        item.checkstate = 2
        }
        }
        //change show 노드가 출력되었지만 이전과 이후 상태가 다른 경우 checkbxo의 표시를 변경합니다.
        if (item.render && pstate != item.checkstate) {
        var et = $("#" id "_" item.id "_cb")
        if (et.length == 1) {
        et.attr("src", dfop.cbiconpath dfop.icons [item.checkstate])
        }
        }
        }

        이제 우리 트리의 주요 기능이 완전히 구현되었습니다. 다른 것들은 일부 메서드 등을 노출하는 것입니다. 자세한 내용은 코드를 볼 수 있습니다. 예제에서는 두 개가 노출되는데, 하나는 현재 선택된 모든 노드이고 다른 하나는 현재 노드입니다.

        다음 홈페이지를 통해 기사 속 예시를 확인하실 수 있습니다. 잘못 선택하신 경우 사과드립니다! Windows Azure 배포는 여전히 번거롭고 한 번에 로드할 3500개의 노드를 수정하기에는 너무 게으릅니다. 루트 노드를 클릭하여 모두 선택하면 속도를 볼 수 있습니다

        http://jscs.cloudapp.net/ControlsSample/BigTreeSample

        비동기 로딩과 주문형 로딩도 매우 일반적입니다. SQL Azure 서버는 미국에서 사용하기 때문에 비동기 로딩이 다소 느릴 수 있지만 로컬 데이터 소스는 순간적입니다.

        http://jscs.cloudapp.net/ControlsSample/TreeAsnySample

        FAQ:

        1: 노드마다 다른 아이콘을 설정하는 방법은 무엇입니까?

        정답:

        사실 확장할 필요도 없고 자체적으로 지원되지만 설명이 없는 코드를 살펴볼까요? BuildNode 메소드에 이런 문장이 있나요?
        if (nd.classes) { cs.push(nd.classes) }

        노드의 데이터 구조에서 속성 클래스를 설정할 수 있으며, 이는 노드에 특수 클래스로 추가됩니다. 노드의 CSS 클래스입니다. 그러면 이를 활용하여 노드의 아이콘을 설정할 수 있습니다

        image

        그런 다음 스타일을 작성하세요

        image

        최종 효과를 살펴볼까요?

        image

        Statement:
        The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn