憨态可掬又丑的梅花雪。DTree中致命的递归。

   
最近的一个类型受到只要对准页面及之Filter中的菜单树进行改造,原因是之前所利用的TreeView控件树于页面初次加载的早晚耗时过长,效率低下(想必用过微软TreeView树控件的用户都起了这么的感受)。改造的骨干想法是故客户端树来顶替从劳动器端加载的TreeView树,客户端构造树只能用javascript了,要体现树的UI和可操控性,就必提供动态的HTML用事件来进展加载(DHTML部分),这是如出一辙起十分麻烦的政工,于是我虽悟出了运用网络达到非常著名的“梅花雪养控件”,不过里面遇的题目多多,梅花雪的作者在求点考虑的题材要不够健全,使得自己当改造梅花雪树的进程遭到相见了成百上千劳神。

   
前不久自己上了同样篇稿子,名字给《可爱而丑的梅花雪》,其中介绍了meizz大侠赫赫有名的梅雪树控件,而且本着内部遇到的部分稍稍题目进行了改造,后来有人评价说梅花雪树太复杂,不如DTree来得简便,这个真的如此!DTree的代码看起要方便很多,所实现之效应也尚生丰富(尽管还没梅花雪树那强),在形似的菜系和导航控制中利用会死方便,而且无会见时有发生啊问题。我当改造梅花雪树之前,也一度尝试了DTree,并且也针对中间的有的方法进行了改造,但后来只好放弃,因为DTree中致命的递归导致了以老大数据量构造树的节点时js报堆栈溢出之错误!

    首先说明一下,这个类别是白手起家以Microsoft最新的店家级Portal Sharepoint
2007平台上,并且根据客户的渴求,所有的Custom
Code只能写在客户端,也就是说整个项目不克于服务器上安排dll(不过前提到的深Filter的TreeView是个不同,那个是利用C#
Webpart编写的),UI的一对截图在脚。

    先看自己本着DTree的改造。

必威电竞 1
在选择Filter之前

    1.
DTree中图纸的援路径为形容深在js代码里,这个了可形容成一个变量,在急需经常移。

必威电竞 2

var
imgPath = “img”;
// Tree object
function dTree(objName) {
    this.config = { target:
null, folderLinks: true,
useSelection: true, useCookies: true,
useLines: true, useIcons: true,
useStatusText: false, closeSameLevel: false,
inOrder: false };
    this.icon = { root:
imgPath + “/base.gif”, folder:
imgPath + “/folder.gif”,
folderOpen: imgPath + “/folderopen.gif”, node:
imgPath + “/page.gif”, empty:
imgPath + “/empty.gif”, line:
imgPath + “/line.gif”, join:
imgPath + “/join.gif”,
joinBottom: imgPath + “/joinbottom.gif”, plus:
imgPath + “/plus.gif”,
plusBottom: imgPath + “/plusbottom.gif”, minus:
imgPath + “/minus.gif”,
minusBottom: imgPath + “/minusbottom.gif”, nlPlus:
imgPath + “/nolines_plus.gif”, nlMinus:
imgPath + “/tree/nolines_minus.gif” };
    this.obj = objName;
    this.aNodes = [];
    this.aIndent = [];
    this.root = new
Node(-1);
    this.selectedNode = null;
    this.selectedFound = false;
    this.completed = false;
}

在选择Filter中的Hierarchy之后

    2.
DTree中无用于获取给选节点的text值的点子,而内部的test方法了好于用来改造。

     Hierarchy的下拉面板中生三蔸树,通过RadioButton进行切换。

// Get
all selected nodes text (e.g. a,b,c,d,e)
dTree.prototype.getText = function ()
{
    var value = new
Array();
    for (var n
= 0; n
< this.aNodes.length; n++) {
        if (this.aNodes[n].check === “true” || this.aNodes[n].check === true) {
            value[value.length] = this.aNodes[n].name;
        }
    }
    return value;
};

   
梅花雪网站上只能找到1.0本的培育,经过改良后底2.0版效果是,但是在梅花雪的网站上类似还无供下载,我当Google达摸了一晃,也或找到多而供应下载的地址。

    3.
DTree中从来不设想节点的CheckBox的disabled状态,由于节点受到自然就是带有CheckBox控件,所以可以一直使用她的disabled属性来开展支配。

必威电竞 3

var
treeMode = “General”;
//General or Special
// Event of the node
check
dTree.prototype.checkNode
= function(nodeId) {
    var check =
document.getElementById((“c” + this.obj)

梅花雪树1.0

  • nodeId);
        var node = this.getNode(nodeId);
        node.check = check.checked;
        if (check.checked) {
            if (treeMode == “Special”) {
                this.enableChildreNode(node, true);
            }
            else {
                this.checkChildreNode(node, true);
            }
            //this.checkParentNode(node, true);
        } else {
            if (treeMode == “Special”) {
                this.enableChildreNode(node, false);
            }
            else {
                this.checkChildreNode(node, false);
            }
        }
    };

必威电竞 4

// Check all child nodes of the current node
(recursive)
dTree.prototype.checkChildreNode
= function
(node, check) {
    for (var i
= 0; i
< node.cNode.length; i++) {
        var pCheck =
document.getElementById((“c” + this.obj)

梅雪树2.0

  • node.cNode[i].id);
            if (pCheck && !pCheck.disabled) {
                pCheck.checked = check;
                node.cNode[i].check = check;
            }
            if (node.cNode[i].cNode.length > 0) {
                this.checkChildreNode(node.cNode[i], check);
            }
        }
    };

   
网络直达产生广大版的梅花雪树,不过造型都差不多,我所用之是带复选框的栽培,并且绑定数据略,最好不用通过递归绑定数据(因为当节罗列了多时,通过递归绑定数据效率太没有,在浏览器中加载树时通常还见面“死机”)。其实需要特别简单,于是我选了点的梅花雪2.0扶植。这个版本确实是,除了可经过不同之艺术绑定数据外,还支持动态加载数据,也就是说在培训之节点进行时才去动态加载节点。只要非以页面初始加载的时光整展开树的节点,页面响应的时日会充分不够。我按照示例中的代码进行了测试,编写js脚本解析数据并绑定到树上,然后运行看成效,还对,一切看起还老健康,于是自己老兴奋,看来好素养快要告成!

dTree.prototype.enableChildreNode = function(node, check) {
    for (var i
= 0; i
< node.cNode.length; i++) {
        var pCheck =
document.getElementById((“c” + this.obj)

    进一步测试并加上相应的需求,问题立马便来了:

  • node.cNode[i].id);
            if (pCheck) {
                pCheck.disabled = check;
                node.cNode[i].check =
    pCheck.checked = (check && !pCheck.disabled);

   
首先是自己哪些获取到已选的节点?后来才理解是实际上是可怜容易的。设好debugger,调试js,跟一下node对象下出哪性或艺术,找到一个bool属性checked,就是它们了,通过遍历MzTreeView下的nodes,判断节点上的checked属性,然后就是可一直拿走到节点的id或text(这半独属性也是以调试js的经过被发觉的,这比较一直去念代码要来得便宜)。

        }
        if (node.cNode[i].cNode.length > 0) {
            this.enableChildreNode(node.cNode[i], check);
        }
    }
}

必威电竞 5

    
说明一下,我多了一个treeMode变量来拓展判定,当值为General时,在树中check节点时其子节点都让check;当值为Special时,在养中check节点时其子节点都为check而且受disabled。enableChildreNode方法用来disabled所有的子节点并且被check。同时,checkChildreNode方法被需要判定子节点的disabled状态,被disabled的子节点其check状态不能够为改。

    
好,既是可以获取到都选的节点,那么即使同意设置什么样节点被挑了,如何做吧?从地方的经过来拘禁,我们唯有待设置这些节点的checked属性为true就执行了,太爱了!那么果然如此呢?前面我说了,梅花雪2.0之树是动态加载节点的,也就是说,节点所在的道岔使没打开,你是沾不顶节点目标的,于是为就无可知安装节点的checked属性了。这便是自家所遇到的中间一个问题,看来梅花雪树的作者忽略了之题材!问题之基本点是咱先是使以那些你想装属性之节点所在的支行打开,但以培养是层次结构,树可能会见发出成千上万交汇,我们得逐级将这些分支打开,只要分支打开了,就能获取到节点目标,于是为即好安装属性之价值了。这便要求您在绑定树之多少时用这些节点的父节点从下向上依次保存起来,在装置时事先以从上到下的逐条打开分支,然后一切历分支下的节点,最后设置这些节点的属性值。下面是自家实现即无异经过的有代码。

    4. 修改了DTree中node方法里Render节点时之风波注册代码。

  1 var hashArea
= new
Hashtable();
  2 var
hashRegion = new
Hashtable();
  3 var
hashCountry = new
Hashtable();
  4 var
hashCompany = new
Hashtable();
  5 var
hashSelectedCompany = new
Hashtable();
  6 var
hashSelectedNodes = new
Hashtable();
  7 
  8 //该function用于解析绑定MzTreeView的数据
  9 function
FillData(arrAreaRegion, arrRegionCountry, arrCountryCompany,
arrSelectedCompany) {
10     hashArea.clear();
11     hashRegion.clear();
12     hashCountry.clear();
13     hashCompany.clear();
14     hashSelectedCompany.clear();
15     hashSelectedNodes.clear();
16     
17     var data
= {};
18 
19     for
(var i = 0; i
< arrSelectedCompany.length; i++) {
20        
hashSelectedCompany.add(arrSelectedCompany[i],
arrSelectedCompany[i]);
21     }
22     
23     data[“-1_Root”]
= “text:
Statuary;”;
24 
25     //fill Area
and Region
26     for
(var i = 0; i
< arrAreaRegion.length – 1;
i++) {
27         if
(arrAreaRegion[i] != “”) {
28             arrTmp =
arrAreaRegion[i].split(“`”);
29             if
(arrTmp.length > 1) {
30                 var a
= arrTmp[0].trim();
31                 var b
= arrTmp[1].trim();
32                 if
(!hashArea.contains(a)) {
33                     hashArea.add(a, “Root”);
34                     data[“Root_” + a]
= “text:” + a
+ “;”;//Area
35                 }
36                 if
(!hashRegion.contains(b + “1”)) {
37                     hashRegion.add(b + “1”, a);
38                     data[a + “_” + b
+ “1”]
= “text:” + b
+ “;”;//Region
39                 }
40             }
41         }
42     }
43 
44     //fill
Country
45     for
(var j = 0; j
< arrRegionCountry.length – 1;
j++) {
46         if
(arrRegionCountry[j] != “”) {
47             arrTmp =
arrRegionCountry[j].split(“`”);
48             if
(arrTmp.length > 1) {
49                 var a
= arrTmp[0].trim();
50                 var b
= arrTmp[1].trim();
51                 if
(!hashCountry.contains(b + “11”)) {
52                     hashCountry.add(b
+ “11”, a
+ “1”);
53                     data[a + “1_” + b
+ “11”]
= “text:” + b
+ “;”;//Country
54                 }
55             }
56         }
57     }
58 
59     //fill
Company
60     var t;
61     for
(var l = 0; l
< arrCountryCompany.length – 1;
l++) {
62         if
(arrCountryCompany[l] != “”) {
63             arrTmp =
arrCountryCompany[l].split(“`”);
64             if
(arrTmp.length > 1) {
65                 t =
arrTmp[1].split(“;#”);
66                 if (t.length
> 1) {
67                     var a
= arrTmp[0].trim();
68                     var b
= t[1].trim();
69                     if
(!hashCompany.contains(b)) {
70                         hashCompany.add(b, a);
71                         data[a + “11_” +
t[0]] = “text:” + b
+ “;”;
72                         if
(hashSelectedCompany.contains(b.split(“-“)[0])) {
73                             data[a + “11_” +
t[0]] += “checked:true;”;
//CompandCode
74                            
hashSelectedNodes.add(a + “11”,
“”);
75                         }
76                     }
77                 }
78             }
79         }
80     }
81     
82     return
data;
83 }
84 
85 //有选择性地打开树被的子,只要分支打开了,该分支下设置也checked=true的节点就能够自动为挑上
86 function
expandNodes(a) {
87     if
(hashSelectedNodes.count >
hashCompany.count / 2) {
88         a.expandAll(“Root”);
89         return;
90     }
91     var
_nodesCountry = new
Hashtable();
92     var
_nodesRegion = new
Hashtable();
93 
94     for
(var i in
hashSelectedNodes._hash) {
95         if
(hashCountry.contains(i)) {
96            
_nodesCountry.add(hashCountry.items(i), “”);
97         }
98     }
99     for
(var j in
_nodesCountry._hash) {
100         if
(hashRegion.contains(j)) {
101            
_nodesRegion.add(hashRegion.items(j), “”);
102         }
103     }
104     //expand
region level
105     for
(var i in
_nodesRegion._hash) {
106         a.expand(i);
107     }
108     //expand
country level
109     for
(var j in
_nodesCountry._hash) {
110         a.expand(j);
111     }
112     //expand
company level
113     for
(var k in
hashSelectedNodes._hash) {
114         a.expand(k);
115     }
116 }

原的代码是:

   
先说明一下,读者也许看得不是蛮知。首先自己如果组织之塑造总共有四重叠,这是自己先了解之,Area-Region-Country-Company,我们若设置的节点位于叶子节点,也即是Company这一级,FillData函数中分三单for循环分别组织了当时四叠,在结尾一叠的时刻自己根据hashSelectedCompany中之价来判定是否如以拖欠节点的checked设置也true,如果安也true,就需保留其的父节点的id到hashSelectedNodes中。在expandNodes函数中,我们需要根据这个hashSelectedNodes来找到相应的Country和Region,然后逐级打开Area、Region、Country,设置为checked=true的节点就见面自动为选上。当然,如果你开始设置时于捎的节点数目很多,这个函数执行的频率不会见杀高,所以我以函数开始的地方补充加了一个断定,如果您所要设置的节点的数目超过持有节点数目的一半,那么自己干脆就是以培养任何进行,而非用重新失逐级打开节点了。还有一个前提条件,那就是MzTreeView在Render完晚,我们设默认expand第一层,否则expandNodes函数在expand
Region的当儿就是会报寻不交对象的谬误。

str += “<input 
name='” + this.obj
+ “‘
id=’c” + this.obj

   
上面的代码中,读者或许会见问,FillData的时候是为此来深受data数组按照MzTreeView所要求的格式填充数据的,为什么我会以中间添加1
暨11啊?这也是自个儿当使MzTreeView时所遇的另外一个题材,即节点id重复怎么收拾

  • node.id + “‘onclick='” + this.obj
    + “.checkNode(” + node.id
    + “)’
    type=’checkbox’ ” + (node.check
    === “true” ? “checked=’checked'” :
    “”) + ”
    />”;

   
先分析MzTreeView中用来绑定数据常常之结构,我用底未肯定是数字,而是文本(因为后台传递过来的数目只有这些):

改造后底代码是:

1 data[“-1_Root”]
= “text:
Statutory”;
2 data[“Root_APAC”]
= “text:
APAC”;
3 data[“APAC_Australia”]
= “text:
Australia”;
4 data[“Australia_Australia”]
= “text:
Australia”;
必威电竞 6

str += “<input
id=’c” + this.obj

    
问题是,子节点和父节点的id重复了。在Render树的时候则非会见报错,但是别的树节点不全,那些跟父节点id相同之子节点不会见于Render出来。一个吓的解决办法就是当这些文件及加加额外之音,使它和父节点的id不又,这就是是我干什么而当Region这同一重合加1,而以Country这等同交汇加11。代码中使用到了一个Hashtable的靶子,这个是好修的方便存储数据用之,读者可参照我事先的相同首日记《在Javascript中实现伪哈希表》。

  • node.id + “‘
    onclick=’javascript: ” + this.obj
    + “.checkNode(\”” + node.id
  • “\”)’
    type=’checkbox’ ” + (node.check
    === “true” ? “checked=’checked'” :
    “”) + ”
    />”;

   
继续测试,发现小节点很在都没起于树中,为什么?调试,跟踪,再调试,再跟…后来算意识问题所在,原来在自我的数据源中寓小括号,又因自是直用节点的号作为id来绑定数据的,MzTreeView的代码中使了正则表达式来展开节点查找,而己后来以调试中发觉这正则表达式没有针对特殊字符进行非常处理,例如我这边碰到的小括声泪俱下(小括号当正则表达式中为是特殊字符),下面是MzTreeView中mzdata.js文件被的原始代码。

   
以上是自己当使DTree时根据需要对DTree的一些改造。下面说说自己所碰到的题材。

1 //public:
getNode (has Builded) by sourceId
2 MzData.prototype.getNodeById = function(id)
3 {
4   if(id==this.rootId&&this.rootNode.virgin) return this.rootNode;
5   var
_=this.get__(), d = this.dividerEncoding;
6   var
reg=new
RegExp(“([^”+_+ d
+”]+”+ d

   
首先,DTree的结构直接用了dTree.add()方法,也就是说要以一个巡回或递归中去add所有的节点,如果先知情树的层级,我们之所以n次循环可以缓解问题,但若是先未知道树的层级,就得采用递归,在js中只要递归过深会引发堆栈溢出底错误。

  • id +”)(“+_+”|$)”);
    7   if(reg.test(this.indexes)){var
    s=RegExp.$1;
    8   if(s=this.dataSource[s].getAttribute(“index_”+ this.hashCode))
    9     return this.nodes[s];
    10   else{System._alert(“The node
    isn’t initialized!”); return null;}}
    11   alert(“sourceId=”+ id
    +” is
    nonexistent!”); return null;
    12 };

   
其次,细查DTree中之代码,发现多地方实在还是故递归实现之算法,这为就算是为什么自己只管解决了以递归中add节点的题材后要么会频频地起堆栈溢出底缪。来看看这些造成错误的殊死的递归。

   
reg.test(this.indexes)判断的结果为false,也就是说reg的正则匹配失败,原因就是id的价值备受蕴含了小括号。我之想法是于开展正则表达式之前将id值中的小括号统一替换成别的字符,然后开展正则表达式匹配,匹配完后再行交替掉小括哀号,下面是自修改后的代码。

    1.
checkChildreNode计中的递归在check一个父节点的时光会硌,如果此父节点下的分段和子节点特别多,即使不抓住堆栈溢出的一无是处,速度估计为不行缓慢。

1 MzData.prototype.getNodeById = function(id)
2 {
3   if(id==this.rootId&&this.rootNode.virgin) return this.rootNode;
4   var
_=this.get__(), d = this.dividerEncoding;
5   //—————-
6   var _id
= id;
7   _id =
_id.replace(/\(/g,
“jackyxu”).replace(/\)/g,
“xujacky”);
8   var _indexes
= this.indexes;
9   _indexes =
_indexes.replace(/\(/g,
“jackyxu”).replace(/\)/g,
“xujacky”);
10   var
reg=new
RegExp(“([^”+_+ d
+”]+”+ d

dTree.prototype.checkChildreNode = function (node, check) {
    for (var i = 0; i < node.cNode.length; i++) {
        var pCheck = document.getElementById((“c” + this.obj) + node.cNode[i].id);
        if (pCheck && !pCheck.disabled) {
            pCheck.checked = check;
            node.cNode[i].check = check;
        }
        if (node.cNode[i].cNode.length > 0) {
            this.checkChildreNode(node.cNode[i], check);
        }
    }
};

  • _id +”)(“+_+”|$)”);
    11   if
    (reg.test(_indexes)) { var s
    = RegExp.$1.replace(/(jackyxu)/g,
    “(“).replace(/(xujacky)/g,
    “)”);
    12   //—————-
    13   if(s=this.dataSource[s].getAttribute(“index_”+ this.hashCode))
    14     return this.nodes[s];
    15   else{System._alert(“The node
    isn’t initialized!”); return null;}}
    16   alert(“sourceId=”+ id
    +” is
    nonexistent!”); return null;
    17 };

    2.
极度致命之地方以此,render树时会调用addNode方法,而addNode方法以会不停调用node方法,这片单道中形成了一个递归调用的经过,如果节点过多,会掀起堆栈溢出底缪。这个递归同样会由于dtree.tostring()方法引起,它调用addNode,然后addNode调用node,之后node又调用addNode…如此反复,最终形成了罪恶之深渊!

   
因为其实不明了用啊字符来替换小括如泣如诉(很多键盘上的字符都被视作正则表达式的特殊字符了),我哪怕用jackyxu来取代“(”,用xujacky来替“)”,正则表达式匹配后更交替回来。在mzdata.js文件被还有一个地方呢用接近修改,下面是原始代码和改后的代码。

// Creates the node icon, url and text
dTree.prototype.node = function (node, nodeId) {
    var str = “<div class=\”dTreeNode\”>” + this.indent(node, nodeId);
    if (this.config.useIcons) {
        if (!node.icon) {
            node.icon = (this.root.id == node.pid) ? this.icon.root : ((node._hc) ? this.icon.folder : this.icon.node);
        }
        if (!node.iconOpen) {
            node.iconOpen = (node._hc) ? this.icon.folderOpen : this.icon.node;
        }
        if (this.root.id == node.pid) {
            node.icon = this.icon.root;
            node.iconOpen = this.icon.root;
        }
        if (node.check && node.check != “”) {
        //  onclick=’alert(nodeId)’
            str += “<input id=’c” + this.obj + node.id + “‘ onclick=’javascript: ” + this.obj + “.checkNode(\”” + node.id + “\”)’ type=’checkbox’ ” + (node.check === “true” ? “checked=’checked'” : “”) + ” />”;
        } else {
            str += “<img id=\”i” + this.obj + nodeId + “\” src=\”” + ((node._io) ? node.iconOpen : node.icon) + “\” alt=\”\” />”;
        }
    }
    if (node.url) {
        str += “<a id=\”s” + this.obj + nodeId + “\” class=\”” + ((this.config.useSelection) ? ((node._is ? “nodeSel” : “node”)) : “node”) + “\” href=\”” + node.url + “\””;
        if (node.title) {
            str += ” title=\”” + node.title + “\””;
        }
        if (node.target) {
            str += ” target=\”” + node.target + “\””;
        }
        if (this.config.useStatusText) {
            str += ” onmouseover=\”window.status='” + node.name + “‘;return true;\” onmouseout=\”window.status=”;return true;\” “;
        }
        if (this.config.useSelection && ((node._hc && this.config.folderLinks) || !node._hc)) {
            str += ” onclick=\”javascript: ” + this.obj + “.s(” + nodeId + “);\””;
        }
        str += “>”;
    } else {
        if ((!this.config.folderLinks || !node.url) && node._hc && node.pid != this.root.id) {
            str += “<a href=\”javascript: ” + this.obj + “.o(” + nodeId + “);\” class=\”node\”>”;
        }
    }
    str += node.name;
    if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) {
        str += “</a>”;
    }
    str += “</div>”;
    if (node._hc) {
        str += “<div id=\”d” + this.obj + nodeId + “\” class=\”clip\” style=\”display:” + ((this.root.id == node.pid || node._io) ? “block” : “none”) + “;\”>”;
        str += this.addNode(node);
        str += “</div>”;
    }
    this.aIndent.pop();
    return str;
};

1 MzDataNode.prototype.loadChildNodes = function(DataNodeClass)
2 {
3   var
$=this.$$caller,r=$.dividerEncoding,_=$.get__(),
i, cs;
4   var
tcn=this.childNodes;tcn.length=0;if(this.sourceIndex){
5   if((i=this.get(“JSData”)))
$.loadJsData((/^\w+\.js(\s|\?|$)/i.test(i)?$.jsDataPath:””)+i);
6   if((i=this.get(“ULData”)))
$.loadUlData(i, this.id);
7   if((i=this.get(“XMLData”)))$.loadXmlData((/^\w+\.xml(\s|\?|$)/i.test(i)?$.xmlDataPath:””)+i,this.id);}
8   var
reg=new RegExp(_
+ this.id

    3.
openTo()方法中之递归和closeAllChildren()方法吃的递归。同样,closeAllChildren()方法被之递归会由closeLevel()方法引起。

  • r +”[^”+ _
  • r +”]+”,
    “g”); 
    9   if((cs=$.indexes.match(reg))){for(i=0;i<cs.length;i++){
    10     tcn[tcn.length]=this.DTO(DataNodeClass,
    cs[i].substr(_.length));}}
    11   this.isLoaded
    = true;
    12 };

dTree.prototype.openTo = function (nId, bSelect, bFirst) {
    if (!bFirst) {
        for (var n = 0; n < this.aNodes.length; n++) {
            if (this.aNodes[n].id == nId) {
                nId = n;
                break;
            }
        }
    }
    var cn = this.aNodes[nId];
    if (cn.pid == this.root.id || !cn._p) {
        return;
    }
    cn._io = true;
    cn._is = bSelect;
    if (this.completed && cn._hc) {
        this.nodeStatus(true, cn._ai, cn._ls);
    }
    if (this.completed && bSelect) {
        this.s(cn._ai);
    } else {
        if (bSelect) {
            this._sn = cn._ai;
        }
    }
    this.openTo(cn._p._ai, false, true);
};

 

 

1 MzDataNode.prototype.loadChildNodes = function(DataNodeClass)
2 {
3   var
$=this.$$caller,r=$.dividerEncoding,_=$.get__(),
i, cs;
4   var
tcn=this.childNodes;tcn.length=0;if(this.sourceIndex){
5   if((i=this.get(“JSData”)))
$.loadJsData((/^\w+\.js(\s|\?|$)/i.test(i)?$.jsDataPath:””)+i);
6   if((i=this.get(“ULData”)))
$.loadUlData(i, this.id);
7   if((i=this.get(“XMLData”)))$.loadXmlData((/^\w+\.xml(\s|\?|$)/i.test(i)?$.xmlDataPath:””)+i,this.id);}
8   //—————-
9   var _id
= this.id;
10   _id =
_id.replace(/\(/g,
“jackyxu”).replace(/\)/g,
“xujacky”);
11   var _indexes
= $.indexes;
12   _indexes =
_indexes.replace(/\(/g,
“jackyxu”).replace(/\)/g,
“xujacky”);
13   var
reg=new RegExp(_

dTree.prototype.closeAllChildren = function (node) {
    for (var n = 0; n < this.aNodes.length; n++) {
        if (this.aNodes[n].pid == node.id && this.aNodes[n]._hc) {
            if (this.aNodes[n]._io) {
                this.nodeStatus(false, n, this.aNodes[n]._ls);
            }
            this.aNodes[n]._io = false;
            this.closeAllChildren(this.aNodes[n]);
        }
    }
};

  • _id + r
    +”[^”+ _
  • r +”]+”,
    “g”); 
    14   if((cs=_indexes.match(reg))){for(i=0;i<cs.length;i++){
    15     tcn[tcn.length]=this.DTO(DataNodeClass,
    cs[i].substr(_.length).replace(/(jackyxu)/g,
    “(“).replace(/(xujacky)/g,
    “)”));}}
    16   //—————-
    17   this.isLoaded
    = true;
    18 };

   
另外,大部分底措施吃都富含了巡回,整个代码的结构即是循环套递归,递归套循环。当节点数少时凡发现不了问题之,节点数多之时节还不只是加载树的经过特别慢,直接就是一个沉重之失实——堆栈溢出!事实上,我所用来测试的数据未超过1000单节点,问题的要就在DTree树不像梅花雪树那样去动态地加载节点,它是一次性将具有的节点都加载了。当然,如果树于小,DTree在应用及还是特别有利的,毕竟她的布局较梅花雪树要简单,也远非那些过多之资源和js脚本需要引入。

   
当然,可能用替换的字符不止是小括如泣如诉,或者中括号、大括号当,但当自身的类型遭到就会赶上使用小括声泪俱下的景,于是自己吧就单单做了这般的改,如果想同一劳永逸,读者可以一般之艺术特别编排一个function进行正则表达式中特殊字符的处理。经过改后底代码可以假设名称被包含小括号的之节点成功在养被展示,于是这个问题便缓解了。

   
最后,我当后要吃有己测试用之代码吧,读者可以以Tree.htm文件中之测试数据开展测试,我受了点儿组数用来测试,一组数据节点比较少,是得正常使用的,一组数据节点很多,会报堆栈溢出底不当。

   
接下是匪是不怕从不问题了吧?不然!梅花雪的以身作则页面中养是于页面load的时刻加载上去的,没有经按钮事件展开加载,就是说当页面上从不数加载的长河,而于自己之需求中是索要如此做的,于是我拿培训之加载过程在一个按钮的事件受到,这样当自家思再次加载树的时段只是需要点击按钮即可,不过这个时候问题虽来了,每次自我点击按钮重复加载树的早晚到底节点前都冒出了不伦不类的空白!看看下面的截图。

代码下载

必威电竞 7    
Statutory是根节点,可是前可出现了空荡荡,似乎梅花雪在树加载的时刻以其看成一个子节点处理了。我试着点了接触这个空白的地方,发现是均等布置图,就是子节点前面的虚线。找到问题所在就好惩治了,看看代码吧!根节点才见面在树Render的时段显得出来,那么问题应该出现在MzTreeView.js文件的Render方法中。

1 MzTreeView.prototype.render = function()
2 {
3   function
loadImg(C){for(var i
in C){if(“string”==typeof
C[i]){
4   var
a=new Image();
a.src=me.iconPath + C[i];
C[i]=a;}}} var
me=this;
5  
loadImg(MzTreeView.icons.expand);loadImg(MzTreeView.icons.collapse);
6   loadImg(MzTreeView.icons.line);
me.firstNode=null;
7   loadCssFile(this.iconPath
+”mztreeview.css”,
“MzTreeView_CSS”);

9   this.initialize(); var
str=”no
data”, i, root=this.rootNode;
10   if
(root.hasChild){var a = [], c
= root.childNodes; me.firstNode=c[0];
11   for(i=0;i<c.length;i++)a[i]=c[i].render(i==c.length-1);str=a.join(“”);}
12   setTimeout(function(){me.afterRender();}, 10);
13   return “<div
class=’mztreeview’ id=’MTV_root_”+ this.index
+”‘
“+
14     “onclick=’Instance(\””+
this.index +”\”).clickHandle(event)’ “+
15     “ondblclick=’Instance(\””+
this.index +”\”).dblClickHandle(event)’ “+
16     “>”+ str
+”</div>”;
17 };

    
然而这个艺术才是以页面及加载了有图和样式表的援,并打有了一个div并让来了风波句柄,没有呀特别之东西。上下随意看了一晃别的部分,发现产生一个MzTreeNode对象,其中也出一个Render方法,仔细看了转,问题即应运而生于此间。

1 MzTreeNode.prototype.render = function(last)
2 {
3   var
$=this.$$caller, s=$.dataSource[this.sourceIndex],target,data,url;
4   var
icon=s.getAttribute(“icon”);
5   if(!(target=s.getAttribute(“target”)))target=$.getDefaultTarget();
6   var
hint=$.showToolTip ?
s.getAttribute(“hint”)
|| this.text :
“”;
7   if(!(url=s.getAttribute(“url”))) url
= $.getDefaultUrl();
8   if(data=s.getAttribute(“data”))url+=(url.indexOf(“?”)==-1?”?”:”&”)+data;

10   var
id=this.index,
s=””;
11   var
isRoot=this.parentNode==$.rootNode;
12   if( isRoot
&& $.convertRootIcon && !icon) icon
= “root”;
13   if(!isRoot)this.childPrefix=this.parentNode.childPrefix+(last?”,ll”:”,l4″);
14   if(!icon
|| typeof(MzTreeView.icons.collapse[icon])==”undefined”)
15   this.icon
= this.hasChild
? “folder” :
“file”;
else this.icon
= icon;
16   this.line
= this.hasChild
? (last ? “pm2” :
“pm1”) : (last
? “l2” :
“l1”);
17   if(!$.showLines)
this.line = this.hasChild
? “pm3” :
“ll”;
18 
19   s += “<div><table border=’0′ cellpadding=’0′
cellspacing=’0′>”+
20        “<tr
title='”+ hint
+”‘><td>”;
if (MzTreeNode.htmlChildPrefix)
21   s +=
MzTreeNode.htmlChildPrefix +”</td><td>”;
if(!isRoot)
22   s += “<img
border=’0′ id='”+ $.index
+”_expand_”+ id
+”‘
src='”+
23        (this.hasChild
? MzTreeView.icons.collapse[this.line].src : 
24        MzTreeView.icons.line[this.line].src)+”‘>”;
if($.showNodeIcon)
25   s += “<img
border=’0′ id='”+ $.index
+”_icon_”+ id
+”‘
src='”+ 
26        MzTreeView.icons.collapse[this.icon].src +”‘>”;
if($.useCheckbox)
27   s += “<img
border=’0′ id='”+$.index
+”_checkbox_”+ id
+”‘
src='”+ 
28        MzTreeView.icons.line[“c”+
(this.checked?1:0)].src
+”‘>”;
29   s += “</td><td style=’padding-left: 3px’
nowrap=’true’><a href='”+ url

  • 30        “‘
    target='”+ target
    +”‘
    id='”+$.index
    +”_link_”+ id
  • 31        “‘
    class=’MzTreeView’>”+ this.text
    +”</a></td></tr></table><div
    “;
    32        if(isRoot&&this.text==””)
    s=”<div><div “;
    33   s += “id='”+$.index+”_tree_”+id+”‘
    style=’display: none;’></div></div>”;
    34   return s;
    35 };

     if
(MzTreeNode.htmlChildPrefix)这句话是因此来判断时节点是否为子节点,如果是的语句虽会补充加图以面前,莫名其妙的是本人的时节点是彻底节点,怎么为会适合这论断标准也?这个当还是梅花雪的一个Bug,不管如此多矣,直接当if中补充加一个判断,即if
(MzTreeNode.htmlChildPrefix &&
!isRoot),如果手上节点是根本节点,则不再添加图了。重新试了转,果然可以了。接下来就是有急需者的略微题目了,例如培植于初始化完毕之后连续会默认将刀口放在根节点上,这个问题特别易解决,可以改样式表将节点获取关节之体制修改掉,或者当MzTreeView.js文件被以节点获取关节的代码去丢。

1 MzTreeView.prototype.afterRender=function()
2 {
3   var
me=this;
4   if(document.getElementById(“MTV_root_”+
me.index))
5   {
6     //if(me.firstNode)(me.currentNode=me.firstNode).focus();
7     this.dispatchEvent(new
System.Event(“onrender”));
8     if(me.useArrow) me.attachEventArrow();
9   }
10   else
setTimeout(function(){me.afterRender();}, 100);
11 };

    
还有一个问题,梅花雪树以动态加载节点时是异步完成的,代码中来咬定,当子节点的多少超过400只时,父节点打开的时刻会来得“正在加载…”,其实这意义还是不错的,给用户的感受是。但是现在培养于默认加载时如拿装有节点不折不扣进展,如果节点数目过多,加载时间也是死丰富的,这个时候并从未出示“正在加载”(梅花雪就针对节点加载做了拍卖,而无对准培训加载做处理),页面会一直待直到整棵树任何加载了。这个时段的用户体验特别坏,如何解决这个题材吗?看来我们惟有和谐写代码来拍卖了!js中发出一个网方法setInterval,它可以以指定的日子距离内履代码,我们可以确定一个光阴段,每隔一个时光段就是展开自我批评,如果树已经加载了便展示树,如果树没加载了便被出一个提醒(文字或图片都好),这个上的用户体验相对会好很多。不过梅雪树本身并无提供用于判断树为加载了的标识,所以我们用在MzTreeView.js文件中上加标识。

    isend——判断树是否让加载了

    lastNode——最后之节点

   
在树Render之前被lastNode赋值(最后一个节点的id),setInterval方法被连判断树是否就给加载了,然后做相应的拍卖,读者可以参见我附件面临之例子。需要修改MzTreeView.js文件中的MzTreeNode.prototype.expandLevel方法如下。

1 MzTreeNode.prototype.expandLevel = function(level) {
2     if (level
<= 0)
return;
3     level–;
var me = this;
4     if
(this.hasChild && !this.expanded) this.expand();
5     if (level
== 1) {
6         if
(this.hasChild) {
7             var $
= this.$$caller;
8             for (i
= 0; i
< this.childNodes.length; i++)
9             if
($.lastNode != “” && this.childNodes[i].text ==
$.lastNode) $.isend = true;
10         }
11     }
12     for
(var x = this.$$caller.index, i = 0, n
= this.childNodes.length; i < n;
i++) {
13         var node
= this.childNodes[i], d = node.index;
if (node.hasChild)
14             setTimeout(“Instance(‘” + x
+ “‘).nodes[‘” + d
+ “‘].expandLevel(” + level
+ “)”,
1);
15     }
16 };

   
不过出只细微的症结,那就是运用上述办法loading树的当儿用于提示用户的gif图片未动了,直到整棵树加载成功。这个题材是由于js本身是单线程处理的言语致的,当js在以setInterval方法加载树的长河被一直会占用CPU的拍卖时,这时就没功夫去处理gif图片的卡通了。感兴趣的读者可以改造附件面临之代码,自己拟多线程使gif图片动起来。不过我最终或放弃了动gif图片进行提醒,改用文字了,反正达到预期的力量即使哼。

   
结论:总体来说,梅花雪树的功用或对的,尤其在动态加载树的节点,采用不同的不二法门绑定数据,并且还可为树的节点提供右键菜单,功能非常强大,也为利用客户端树的开发人员提供了要命挺之便宜。个人认为,web开发被采用客户端树总比采用服务器端树效率要大,但复杂度高而难以控制,适当并不无道理地借鉴前人的经验,将会看去过多未必要之累。虽然梅花雪树经过了2只版本,但是于实质上采用被还是暴露了众底问题,作者给闹底支付文档和注释也不周全,园子里产生成千上万热心的朋友还对梅花雪树改造了,希望大家可以共同努力,打造一个效果又强、更完善的花魁雪树!!

   
顺便让闹梅花雪树2.0蒙受重要文件的证实,其中标记为红的是生死攸关修改的公文或者资源。为了适应自己的项目,经过改动后底梅雪树被去除了部分从没因此的公文(如使用js和xml文件绑定数据等),修改了有的加载资源的不二法门等。

scripts\csdn\community\treedata\ 该目录下的文件用于绑定树的数据源,包括js文件和xml文件。
scripts\jsframework.js mztreeview主框架代码文件。
scripts\system\_resource\mztreeview\ 主要资源文件,包括样式表和图片。
scripts\system\data\mzdata.js 用于处理mztreeview节点数据。
scripts\system\net\mzcookie.js mztreeview的状态可以保存到cookie中,该文件用于处理cookie的保存和获取。
scripts\system\plugins\ 支持多浏览器版本数据加载的处理。
scripts\system\web\ui\webcontrols\mztreeview.js 生成mztreeview主结构的代码文件。
scripts\system\web\forms\mzeffect.js mztreeview特殊效果处理文件。
scripts\system\xml\mzxmldocument.js 用于处理xml文档。
scripts\system\global.js mztreeview全局配置文件。

梅花雪树1.0下蛋充斥
梅雪树2.0下充斥
经修改后底梅花雪树

相关文章

admin

网站地图xml地图