您的位置:首页 > Web前端 > JavaScript

用JavaScript实现一个简单的树结构

2012-02-05 00:00 627 查看
数据源用数组混json结构,实现了基本的功能。效率一般,跟 dhtree 梅花雪树对比了下,都差不多。 (ps感觉比dhtree快点,跟梅花雪树差不多,个人测试)


这个实现树的原理是根据json,不断的生成ul li, 下面是一个简单的例子(只有涉及到生成树,也就是说只是展示,tree类代码只有64行) 没有用innerHTML生成,全是是创建节点来创建ul li,所以创建节点碎片添加,然后再一次性添加很重要啊,确实能提高速度。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb-2312" />
<title>easytree</title>
<style type="text/css">
ul,li{
list-style: none outside none;
margin: 0;
overflow: hidden;
padding: 0;
}
#demo{
background-color:#F0FBEB;
}
#demo .root{
margin-left: -20px;
}
#demo ul{
padding-left: 20px;
}
#demo .folder{
background: url("../../images/201202/r_i.png") repeat-y scroll 0 21px transparent;
}
#demo img{
background: url("../../images/201202/r_icon.png") no-repeat scroll 0 0 transparent;
border: medium none;
height: 20px;
vertical-align: top;
width: 20px;
}
#demo .tvicon-open{
background-position: -160px -40px;
}
#demo .tvdash-f{
background-position: -240px -40px;
}
#demo .tvdash-f-open{
background-position: -200px -40px;
}
#demo .tvdash-fl{
background-position: -100px -40px;
}
#demo .tvdash-fl-open{
background-position: -80px -40px;
}
#demo .tvdash-t{
background-position: -180px -40px;
}
#demo .tvdash-tl{
background-position: -60px -40px;
}
</style>
</head>
<body>
<div id='sss'></div>
<div id='demo'></div>
<script>
(function(doc,undefined){
var window = this;
window.Sys = function (ua){
var b = {
ie: /msie/.test(ua) && !/opera/.test(ua),
opera: /opera/.test(ua),
safari: /webkit/.test(ua) && !/chrome/.test(ua),
firefox: /firefox/.test(ua),
chrome: /chrome/.test(ua)
},vMark = "";
for (var i in b) {
if (b[i]) { vMark = "safari" == i ? "version" : i; break; }
}
b.version = vMark && RegExp("(?:" + vMark + ")[\\/: ]([\\d.]+)").test(ua) ? RegExp.$1 : "0";
b.ie6 = b.ie && parseInt(b.version, 10) == 6;
b.ie7 = b.ie && parseInt(b.version, 10) == 7;
b.ie8 = b.ie && parseInt(b.version, 10) == 8;
return b;
}(window.navigator.userAgent.toLowerCase());
window.Sys.ie6&&doc.execCommand("BackgroundImageCache", false, true);
window.$$ = function(Id){
return doc.getElementById(Id);
};
window.$c = function(name,parent){
var elem = doc.createElement(name);
parent&&parent.appendChild(elem);
return elem;
};
window.addListener = function(element,e,fn){
!element.events&&(element.events = {});
element.events[e]&&(element.events[e][addListener.guid++]=fn)||(element.events[e] = {'0':fn});
element.addEventListener?element.addEventListener(e,fn,false):element.attachEvent("on" + e,fn);
};
window.addListener.guid = 1;
window.removeListener = function(element,e,fn){
var handlers = element.events[e],type;
if(fn){
for(type in handlers)
if(handlers[type]===fn){
element.removeEventListener?element.removeEventListener(e,fn,false):element.detachEvent("on" + e,fn);
delete handlers[type];
}
}else{
for(type in handlers){
element.removeEventListener?element.removeEventListener(e,handlers[type],false):element.detachEvent("on" + e,handlers[type]);
delete handlers[type];
}
}
};
window.setStyle = function(e,o){
if(typeof o=="string")
e.style.cssText=o;
else
for(var i in o)
e.style[i] = o[i];
};
var slice = Array.prototype.slice;
window.Bind = function(object, fun) {
var args = slice.call(arguments).slice(2);
return function() {
return fun.apply(object, args);
};
};
window.BindAsEventListener = function(object, fun,args) {
var args = slice.call(arguments).slice(2);
return function(event) {
return fun.apply(object, [event || window.event].concat(args));
}
};
//copy from jQ
window.extend = function(){
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = true, options;
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
i = 2;
}
if ( typeof target !== "object" && Object.prototype.toString.call(target)!="[object Function]")
target = {};
for(;i<length;i++){
if ( (options = arguments[ i ]) != null )
for(var name in options){
var src = target[ name ], copy = options[ name ];
if ( target === copy )
continue;
if ( deep && copy && typeof copy === "object" && !copy.nodeType ){
target[ name ] = arguments.callee( deep, src || ( copy.length != null ? [ ] : { } ), copy );
}
else if(copy !== undefined)
target[ name ] = copy;
}
}
return target;
};
//copy from jQ
window.each = function ( object, callback, args ) {
var name, i = 0, length = object.length;
if ( args ) {
args = Array.prototype.slice.call(arguments).slice(2);
if ( length === undefined ) {
for ( name in object )
if ( callback.apply( object[ name ],[name,object[ name ]].concat(args) ) === false )
break;
} else
for ( ; i < length; i++)
if ( callback.apply( object[ i ],[i,object[ i ]].concat(args)) === false ) //
break;
} else {
if ( length === undefined ) {
for ( name in object )
if ( callback.call( object[ name ], name, object[ name ] ) === false )
break;
} else
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
}
return object;
};
window.currentStyle = function(element){
return element.currentStyle || doc.defaultView.getComputedStyle(element, null);
};
window.objPos = function(elem){
var left = 0, top = 0, right = 0, bottom = 0,doc = elem ? elem.ownerDocument : doc;
if ( !elem.getBoundingClientRect || window.Sys.ie8 ) {
var n = elem;
while (n) { left += n.offsetLeft, top += n.offsetTop; n = n.offsetParent; };
right = left + elem.offsetWidth; bottom = top + elem.offsetHeight;
} else {
var rect = elem.getBoundingClientRect();
left = right = doc.documentElement.scrollLeft || doc.body.scrollLeft;
top = bottom = doc.documentElement.scrollLeft || doc.body.scrollLeft;
left += rect.left; right += rect.right;
top += rect.top; bottom += rect.bottom;
}
return { "left": left, "top": top, "right": right, "bottom": bottom };
};
window.hasClass = function(element, className){
return element.className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'));
};
window.addClass = function(element, className){
!window.hasClass(element, className)&&(element.className += " "+className);
};
window.removeClass = function(element, className){
window.hasClass(element, className)&&(element.className = element.className.replace(new RegExp('(\\s|^)'+className+'(\\s|$)'),' '));
}
})(document);
//------------------------------------------------------------
(function(doc,undefined){
var win = this;
win.easyTree = function(){
this.init.apply(this,arguments);
};
win.easyTree.prototype = {
options : {
},
init : function(options){
this.deflaut = extend(this.options,options);
this.container = options.container;
this.data = options.data;
//根节点直接在这里生成
if(this.data.length>=1){
var ul = $c('ul',this.container),
self = this,
li;
each(this.data,function(i,o){
li = $c('li',ul);
li.className = 'root';
li.innerHTML = '<img src="http://images.cnblogs.com/cnblogs_com/wtcsy/294024/r_space.png" class="tvicon-open"><a href="#">'+o.name+'</a>';
o.child
&&self.bulidTree(o.child,li,'t')
});
}
},
bulidTree : function(data,parent,first){
if(data.length===0)
return;
var ul = $c('ul',parent),
self = this,
len = data.length,
imgClassName,
li;
first
? ul.style.paddingLeft = '0px'
: ul.style.display = 'none';
each(data,function(i,o){
var isLast = (len-1)===i;
li = $c('li',ul);
li.className = 'folder'+(isLast?'l':'');
imgClassName = o.child
? isLast?'tvdash-fl':'tvdash-f'
: isLast?'tvdash-tl':'tvdash-t';
li.innerHTML = '<img src="http://images.cnblogs.com/cnblogs_com/wtcsy/294024/r_space.png" class="'+imgClassName+'"><a href="#">'+o.name+'</a>';
img = li.getElementsByTagName('img')[0];
addListener(img,'click',BindAsEventListener(self,self.openOrClose,li,img));
o.child
&&self.bulidTree(o.child,li);
});
},
openOrClose : function(e,li,img){
var ul = li.getElementsByTagName('ul')[0];
if(ul){
ul.style.display = ul.style.display === 'none'?'':'none';
var name = img.className,
is = img.className.indexOf('open')>-1;
img.className = is?name.replace('-open',''):name+'-open';
}
}
}
})(document);
window.onload = function(){
var i = 0;
var data = [{id:i,name:'根节点',child:[]}];
while(i<100){
i++;
data[0].child.push({id:i,name:'节点'+i,child:[
{id:i*10+1,name:'节点'+i+'-1',child:[
{id:i*11+1,name:'节点'+i+'-1-2'},
{id:i*11+2,name:'节点'+i+'-1-3'},
{id:i*11+3,name:'节点'+i+'-1-4'}
]},
{id:i*10+2,name:'节点'+i+'-2',child:[
{id:i*11+4,name:'节点'+i+'-2-2'},
{id:i*11+5,name:'节点'+i+'-2-3'},
{id:i*11+6,name:'节点'+i+'-2-4'}
]},
{id:i*10+3,name:'节点'+i+'1-3'}
]});
}
var t = new Date().getTime();
new easyTree({
container : $$('demo'),
data : data
});
$$('sss').innerHTML ='一共1000个节点 共耗时:'+ (new Date().getTime()-t)+'毫秒'
}
</script>
</body>
</html>


上面只是一个简单的树,但是树应该是有input的,并且能够选中。记录选中能够开打任何节点,能够删除,不能够编辑、保存。说一下我在这里怎么完成上面的功能。选中应该是比较麻烦的,因为选中了一个节点,要让他所有的子节点都选中,他的父节点也有可能要选中(如果同级的都是选中状态的)。接着他的父的父也有可能要选中,所以设计到很多的查找,当生成一个li的时候,给li一个属性:


li.child.push({
                    li    : li,
                    input : isInput ?$q('input',li)[0]:undefined,
                    data  : o
                });


记录下他下一级(是下一级 不是所有的子 )的所有的input 和li同时记录父的li 和 input:


li.parent = {
                    li    : parent,
                    input : isInput ?$q('input',parent)[0]:undefined
                };


这样查找起来很方便,但是内存就要用的多些了。



<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb-2312" />
<title>easytree</title>
<style type="text/css">
body{font:12px/1.5 '宋体',tahoma;}
ul,li{
list-style: none outside none;
margin: 0;
overflow: hidden;
padding: 0;
}
#demo span{
background: url("../../images/201202/icon.png") no-repeat scroll 0 0 transparent;
border: medium none;
height: 20px;
vertical-align: top;
width: 20px;
display :inline-block;
}
#demo .root{
margin-left: -20px;
}
#demo .root input{
vertical-align: middle;
}
#demo ul{
padding-left: 20px;
}
#demo .folder{
background: url("../../images/201202/i.gif") repeat-y scroll 0 21px transparent;
}
#demo img{
background: url("../../images/201202/icon.png") no-repeat scroll 0 0 transparent;
border: medium none;
height: 20px;
vertical-align: top;
width: 20px;
}
#demo .tvicon-open{
background-position: -160px -40px;
}
#demo .tvdash-f{
background-position: -240px -40px;
}
#demo .tvdash-f-open{
background-position: -200px -40px;
}
#demo .tvdash-fl{
background-position: -100px -40px;
}
#demo .tvdash-fl-open{
background-position: -80px -40px;
}
#demo .tvdash-t{
background-position: -180px -40px;
}
#demo .tvdash-tl{
background-position: -60px -40px;
}
#demo .tvicon-f{
background-position: -120px -40px;
}
#demo .tvicon-f-open{
background-position: -140px -40px;
}
#demo .tvicon-tl{
background-position: -220px -40px;
}
</style>
</head>
<body>
<div id='sss'></div>
<div>
输入id值<br>
<input value='101' type="text" id='v'>
<input value='展开节点'type="button"onClick="ch(document.getElementById('v').value)"><br><br>
返回的是节点id值 也可以是主键值
<input value='查看有多少节点被选中了'type="button"onClick="ss(this.value)">
<br>
</div>
<div id='demo'></div>
<script>
(function(doc,undefined){
var window = this;
window.Sys = function (ua){
var b = {
ie: /msie/.test(ua) && !/opera/.test(ua),
opera: /opera/.test(ua),
safari: /webkit/.test(ua) && !/chrome/.test(ua),
firefox: /firefox/.test(ua),
chrome: /chrome/.test(ua)
},vMark = "";
for (var i in b) {
if (b[i]) { vMark = "safari" == i ? "version" : i; break; }
}
b.version = vMark && RegExp("(?:" + vMark + ")[\\/: ]([\\d.]+)").test(ua) ? RegExp.$1 : "0";
b.ie6 = b.ie && parseInt(b.version, 10) == 6;
b.ie7 = b.ie && parseInt(b.version, 10) == 7;
b.ie8 = b.ie && parseInt(b.version, 10) == 8;
return b;
}(window.navigator.userAgent.toLowerCase());
window.Sys.ie6&&doc.execCommand("BackgroundImageCache", false, true);
window.$$ = function(Id){
return doc.getElementById(Id);
};
window.$q = function(name,parent){
return parent.getElementsByTagName(name);
};
window.$c = function(name,parent){
var elem = typeof name==='object'?name:doc.createElement(name);
parent&&parent.appendChild(elem);
return elem;
};
window.addListener = function(element,e,fn){
!element.events&&(element.events = {});
element.events[e]&&(element.events[e][addListener.guid++]=fn)||(element.events[e] = {'0':fn});
element.addEventListener?element.addEventListener(e,fn,false):element.attachEvent("on" + e,fn);
};
window.addListener.guid = 1;
window.removeListener = function(element,e,fn){
var handlers = element.events[e],type;
if(fn){
for(type in handlers)
if(handlers[type]===fn){
element.removeEventListener?element.removeEventListener(e,fn,false):element.detachEvent("on" + e,fn);
delete handlers[type];
}
}else{
for(type in handlers){
element.removeEventListener?element.removeEventListener(e,handlers[type],false):element.detachEvent("on" + e,handlers[type]);
delete handlers[type];
}
}
};
window.setStyle = function(e,o){
if(typeof o=="string")
e.style.cssText=o;
else
for(var i in o)
e.style[i] = o[i];
};
var slice = Array.prototype.slice;
window.Bind = function(object, fun) {
var args = slice.call(arguments).slice(2);
return function() {
return fun.apply(object, args);
};
};
window.BindAsEventListener = function(object, fun,args) {
var args = slice.call(arguments).slice(2);
return function(event) {
return fun.apply(object, [event || window.event].concat(args));
}
};
//copy from jQ
window.extend = function(){
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = true, options;
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
i = 2;
}
if ( typeof target !== "object" && Object.prototype.toString.call(target)!="[object Function]")
target = {};
for(;i<length;i++){
if ( (options = arguments[ i ]) != null )
for(var name in options){
var src = target[ name ], copy = options[ name ];
if ( target === copy )
continue;
if ( deep && copy && typeof copy === "object" && !copy.nodeType ){
target[ name ] = arguments.callee( deep, src || ( copy.length != null ? [ ] : { } ), copy );
}
else if(copy !== undefined)
target[ name ] = copy;
}
}
return target;
};
//copy from jQ
window.each = function ( object, callback, args ) {
var name, i = 0, length = object.length;
if ( args ) {
args = Array.prototype.slice.call(arguments).slice(2);
if ( length === undefined ) {
for ( name in object )
if ( callback.apply( object[ name ],[name,object[ name ]].concat(args) ) === false )
break;
} else
for ( ; i < length; i++)
if ( callback.apply( object[ i ],[i,object[ i ]].concat(args)) === false ) //
break;
} else {
if ( length === undefined ) {
for ( name in object )
if ( callback.call( object[ name ], name, object[ name ] ) === false )
break;
} else
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
}
return object;
};
window.currentStyle = function(element){
return element.currentStyle || doc.defaultView.getComputedStyle(element, null);
};
window.objPos = function(elem){
var left = 0, top = 0, right = 0, bottom = 0,doc = elem ? elem.ownerDocument : doc;
if ( !elem.getBoundingClientRect || window.Sys.ie8 ) {
var n = elem;
while (n) { left += n.offsetLeft, top += n.offsetTop; n = n.offsetParent; };
right = left + elem.offsetWidth; bottom = top + elem.offsetHeight;
} else {
var rect = elem.getBoundingClientRect();
left = right = doc.documentElement.scrollLeft || doc.body.scrollLeft;
top = bottom = doc.documentElement.scrollLeft || doc.body.scrollLeft;
left += rect.left; right += rect.right;
top += rect.top; bottom += rect.bottom;
}
return { "left": left, "top": top, "right": right, "bottom": bottom };
};
window.hasClass = function(element, className){
return element.className.match(new RegExp('(\\s|^)'+className+'(\\s|$)'));
};
window.addClass = function(element, className){
!window.hasClass(element, className)&&(element.className += " "+className);
};
window.removeClass = function(element, className){
window.hasClass(element, className)&&(element.className = element.className.replace(new RegExp('(\\s|^)'+className+'(\\s|$)'),' '));
}
})(document);
//------------------------------------------------------------------------------------
(function(doc,undefined){
var win = this,
primary;
win.easyTree = function(){
this.init.apply(this,arguments);
};
win.easyTree.prototype = {
options : {
primary : 'id',
isInput : false,
isIco : false
},
init : function(options){
this.deflaut = extend(this.options,options);
this.container = options.container;
//数据源 形式{id:data[i]}
this.data={};
//被勾选的项
this.selected = {};
//根节点直接在这里生成
if(options.data.length>=1){
primary = this.deflaut.primary;
var frag=document.createDocumentFragment()
var ul = $c('ul',frag),//this.container
self = this,
input = this.deflaut.isInput?'<input type="checkbox">':'',
li;
each(options.data,function(i,o){
li = $c('li',ul);
li.className = 'root';
li.innerHTML = [
'<span class="tvicon-open"></span>',
input,
'<a href="#">'+o.name+'</a>'
].join('');
li.setAttribute('primary',o[primary]);
self.data[o[primary]] = {elem:li,data:o};
o.child
&&self.bulidTree(o.child,li,'t');
});
//只绑定一个节点 展开和checkedbox判断都在里面
addListener(ul,'click',BindAsEventListener(self,self.operation));
this.container.appendChild(frag);
}
},
bulidTree : function(data,parent,first){
if(data.length===0)
return;
var ul = $c('ul',parent),
self = this,
len = data.length,
isInput = this.deflaut.isInput,
input = isInput?'<input type="checkbox">':'',
isIco = this.deflaut.isIco,
imgClassName,
img,
li;
first
? ul.style.paddingLeft = '0px'
: ul.style.display = 'none';
parent.child = [];
each(data,function(i,o){
var isLast = (len-1)===i,
ico = isIco
? o.child
? '<span class="tvicon-f"></span>'
: '<span class="tvicon-tl"></span>'
: '';
li = $c('li',ul);
li.className = 'folder'+(isLast?'l':'');
imgClassName = o.child
? isLast?'tvdash-fl':'tvdash-f'
: isLast?'tvdash-tl':'tvdash-t';
li.innerHTML = [
'<span class="'+imgClassName+'"></span>',
ico,
input,
'<a href="#">'+o.name+'</a>'
].join('');
//当前li保存父li的相关信息 只是一个对象
li.parent = {
li : parent,
input : isInput ?$q('input',parent)[0]:undefined
};
//当前li保存子li的相关信息 是一个数组
parent.child.push({
li : li,
input : isInput ?$q('input',li)[0]:undefined,
data : o
});
li.setAttribute('primary',o[primary]);
li.getElementsByTagName('span')[0].setAttribute('mark','mark');
self.data[o[primary]] = {elem:li,data:o};
o.child
&&self.bulidTree(o.child,li);
});
},
operation : function(e){
var elem = e.srcElement || e.target,
nodeName = elem.nodeName.toLocaleLowerCase();
/*显示隐藏子菜单*/
if((nodeName==='span'&&elem.getAttribute('mark'))||(nodeName==='a')){
var li = elem.parentNode,
ul = $q('ul',li)[0],
img = $q('span',li)[0],
ico = $q('span',li)[1];
if(ul){
ul.style.display = ul.style.display === 'none'?'':'none';
var name = img.className,
is = img.className.indexOf('open')>-1;
img.className = is?name.replace('-open',''):name+'-open';
if(ico){
ico.className = is?ico.className.replace('-open',''):ico.className+'-open';
}
}
};
//选中checkedbox的时候的相应的操作
if(nodeName==='input'){
var isCheck = elem.checked,
li = elem.parentNode,
ul = $q('ul',li)[0],
id = li.getAttribute('primary'),
//该元素的索引是否已经添加到了 this.selected中
isIn = id in this.selected;

//操作this.selected 从里面添加或者删除
isCheck
? !isIn
&&(this.selected[id]=id)
: isIn
&&delete this.selected[id];
this.findChild(li,isCheck);
this.findParent(li,isCheck);
}
},
findParent : function(child,b){
if(!child.parent)
return;
var parentLi = child.parent.li,
id = parentLi.getAttribute('primary')
isAll = true;
if(b){
//看他父下面的所有li是不是都是选中状态的
each(parentLi.child,function(i,o){
if(!o.input.checked){
isAll = false;
return false;
}
});
//如果都是选中状态
//继续查找他的父
if(isAll){
child.parent.input.checked = true;
!(id in this.selected)
&&(this.selected[id] = id);
this.findParent(parentLi,b);
}
}else{
if(child.parent.input.checked){
child.parent.input.checked = false;
id in this.selected
&& delete this.selected[id];
this.findParent(parentLi,b);
}
}
},
/*
查找子节点 将所有没有选中的字节点选中 并放到this.selected里面去
或者取消所有的子节点
*/
findChild : function(parent,b){
if(!parent.child)
return;
var self = this;
b
? each(parent.child,function(i,o){
if(!o.input.checked){
o.input.checked = true;
!(o.data[primary] in self.selected)
&&(self.selected[o.data[primary]] = o.data[primary]);
o.li.child
&&self.findChild(o.li,b);
}
})
: each(parent.child,function(i,o){
if(o.input.checked){
o.input.checked = false;
o.data[primary] in self.selected
&& delete self.selected[o.data[primary]];
o.li.child
&&self.findChild(o.li,b);
}
});
},
getAllSelect : function(){
var arr = [],
id;
for(id in this.selected)
arr.push(id);
return arr.join(',')
},
openNode : function(id){
if(id in this.data){
var li = this.data[id].elem,
parent = li.parentNode,
img,
ico;
while(parent.style.display==='none'){
parent.style.display = '';
li = li.parent.li;
img =$q('span',li)[0];
ico =$q('span',li)[1];
img.className=img.className+'-open';
ico
&&(ico.className=ico.className+'-open');
parent = li.parentNode;
}
}
}
}
})(document);
window.onload = function(){
var i = 0,j=100;
var data1 = [{id:i,name:'根节点',child:[]}];
while(i<100){
i++;
data1[0].child.push({id:i,name:'节点'+i,child:[
{id:++j,name:'节点'+i+'-1',child:[
{id:++j,name:'节点'+i+'-1-1'},
{id:++j,name:'节点'+i+'-1-2'},
{id:++j,name:'节点'+i+'-1-3'}
]},
{id:++j,name:'节点'+i+'-2',child:[
{id:++j,name:'节点'+i+'-2-1'},
{id:++j,name:'节点'+i+'-2-2'},
{id:++j,name:'节点'+i+'-2-3'}
]},
{id:++j,name:'节点'+i+'-3-1'}
]});
}

var t = new Date().getTime();
window.tt= new easyTree({
container : $$('demo'),
isInput : true,
isIco : true,
data : data1
});
//alert(new Date().getTime()-t1)
$$('sss').innerHTML ='一共1000个节点 共耗时:'+ (new Date().getTime()-t)+'毫秒'

}
function ch(v){
tt.openNode(v)
}
function ss(){
alert(tt.getAllSelect());
}
</script>
</body>
</html>


基本能达到要求了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: