(function(wdo) { var w = wdo || window, dom = w.document; var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } }; var Stack = Class.create(); Stack.prototype = { initialize: function() { this.stack = new Array(); }, push: function(o) { this.stack.push(o); }, pop: function() { if(this.stack.length - 1 < 0) return null; var o = this.stack[this.stack.length-1]; this.stack.splice(this.stack.length-1, 1); return o; }, isEmpty: function() { if(this.stack.length > 0) return false; else return true; }, size: function() { return this.stack.length; } }; var Tree = Class.create(); Tree.prototype = { initialize: function(options) { this._treedata = options.treedata; this._renderTo = options.renderTo; this._showRoot = options.showRoot; this._htmlRootNode = null; this._clickEvt = null; this._imgUrl = { //minus: "url(images/minus.gif)", //minus1: "url(images/minus1.gif)", minus2: "url(images/minus2.gif)", minus3: "url(images/minus3.gif)", //minus4: "url(images/minus4.gif)", //minus5: "url(images/minus5.gif)", //plus: "url(images/plus.gif)", //plus1: "url(images/plus1.gif)", plus2: "url(images/plus2.gif)", plus3: "url(images/plus3.gif)", //plus4: "url(images/plus4.gif)", //plus5: "url(images/plus5.gif)", line: "url(images/line.gif)", //line1: "url(images/line1.gif)", line2: "url(images/line2.gif)", line3: "url(images/line3.gif)", //line4: "url(images/line4.gif)", oFile: "url(images/folderOpen_bak.gif)", cFile: "url(images/folderClosed_bak.gif)", leaf: "url(images/leaf_bak.gif)" }; this.loopTree(this._treedata[0]); }, addClickEvt: function(fn) { this._clickEvt = fn; }, elastic: function(dpy, flag, img1, img2, img3) { var stack = new Stack(); //判断是否有根节点 if(this._showRoot) { //stack.push(this._htmlRootNode); stack.push(this._htmlRootNode.childrenbox); } else { var list = this._htmlRootNode.childrenbox.childNodes; for(var i = 1 ; i < list.length ; i+=2) { stack.push(list[i]); } } while(!stack.isEmpty()) { var obj = stack.pop(); obj.style.display = dpy; if(obj._first) { obj._first.isExpand = flag; if(obj._first.isLast) { obj._first.style.backgroundImage = img1; } else { obj._first.style.backgroundImage = img2; } obj._second.style.backgroundImage = img3; } var arr = obj.childNodes; for(var i = 1 ; i < arr.length ; i+=2) { stack.push(arr[i]); } } }, expand: function() { this.elastic('block', true, this._imgUrl.minus2, this._imgUrl.minus3, this._imgUrl.oFile); }, shrink: function() { this.elastic('none', false, this._imgUrl.plus2, this._imgUrl.plus3, this._imgUrl.cFile); }, getStringByteLength: function (val){ var Zhlength=0;// 全角 var Enlength=0;// 半角 for(var i=0;i<val.length;i++){ if(val.substring(i, i + 1).match(/[^\x00-\xff]/ig) != null) Zhlength+=1; else Enlength+=1; } // 返回当前字符串字节长度 return (Zhlength*2)+Enlength; }, createNode: function(ops) { var text = ops.text, //节点的文本信息 data = ops.data, //节点的用户数据 parent = ops.parent, //节点的父亲节点 isLeaf = ops.isLeaf, //是否为页节点 isLastNode = ops.isLastNode ; //判断是否为父亲的最后一个子节点 //节点容器 ========== var nodebox = dom.createElement('div'); nodebox.style.cssText = 'border:0px solid red;height:18px;font-size:0px;line-height:0px;'; nodebox.userData = data; //处理节点前面的图标 ========= var stack = new Stack(), tempNode = parent, count = 0; while(tempNode) { count++; stack.push(tempNode); tempNode = tempNode._parent; } if(!this._showRoot) { //判断是否显示根节点 count--; stack.pop(); } //计算节点容器的宽度 count += 2; var len = this.getStringByteLength(text)*6+count*18; nodebox.style.width = (len+10)+'px'; while(!stack.isEmpty()) { var node = dom.createElement('div'); node.style.cssText = '18px;height:18px;float:left;'; var element = stack.pop(); if(element == null) { continue; } else if(element.isLast) { node.style.backgroundImage = ''; } else { node.style.backgroundImage = this._imgUrl.line; } nodebox.appendChild(node); } stack = null; var self = this; //子节点容器 var childrenbox = dom.createElement('div'); childrenbox.style.cssText = 'font-size:0px;line-height:0px;'; //判断是否为叶节点 var node = dom.createElement('div'); nodebox.isLast = isLastNode; if(!isLeaf) { node.style.cssText = '18px;height:18px;float:left;background-image:'+this._imgUrl.minus3; node.isExpand = true; node.isLast = isLastNode; node.isFirst = true; node.onclick = function() { //是否第一次点击 if(this.isFirst) { this._height = nodebox.childrenbox.clientHeight; this.isFirst = false; } var targetHeight = 0; if(this.isExpand) { childrenbox.style.display = 'none'; targetHeight = 0; if(this.isLast) { this.style.backgroundImage = self._imgUrl.plus2; } else { this.style.backgroundImage = self._imgUrl.plus3; } fileNode.style.backgroundImage = self._imgUrl.cFile; this.isExpand = false; } else { childrenbox.style.display = 'block'; targetHeight = this._height; if(this.isLast) { this.style.backgroundImage = self._imgUrl.minus2; } else { this.style.backgroundImage = self._imgUrl.minus3; } fileNode.style.backgroundImage = self._imgUrl.oFile; this.isExpand = true; } } //判断是否为父亲的最后一个子节点 if(isLastNode) { node.style.backgroundImage = this._imgUrl.minus2; } nodebox.appendChild(node); //添加文件夹 var fileNode = dom.createElement('div'); fileNode.style.cssText = '18px;height:18px;float:left;background-image:'+this._imgUrl.oFile; nodebox.appendChild(fileNode); childrenbox._first = node; childrenbox._second = fileNode; } else { node.style.cssText = '18px;height:18px;float:left;background-image:'+this._imgUrl.line3; //判断是否为父亲的最后一个节点 if(isLastNode) { node.style.backgroundImage = this._imgUrl.line2; } nodebox.appendChild(node); node = dom.createElement('div'); node.style.cssText = '18px;height:18px;float:left;background-image:'+this._imgUrl.leaf; nodebox.appendChild(node); } //加入文本信息 var node = dom.createElement('div'); node.style.cssText = 'height:18px;font-size:12px;line-height:18px;text-align:left;float:left;cursor:pointer;'; node.innerHTML = text; node.onclick = function() { //alert(text); self._clickEvt && self._clickEvt(text); } nodebox.appendChild(node); //引用 nodebox.childrenbox = childrenbox; //将当前节点加入到目标节点 if(parent) { parent.childrenbox.appendChild(nodebox); parent.childrenbox.appendChild(childrenbox); nodebox._parent = parent; } return nodebox; }, loopTree: function(root) { var nodeStack = new Stack(), htmlStack = new Stack(), node = null, isLeaf = true, htmlNode = null, htmlRootNode = null; nodeStack.push(root); //创建根节点 htmlNode = htmlRootNode = this.createNode({ text: root.name, data: root.data, parent: htmlNode, isLeaf: false, isLastNode: true }); htmlStack.push(htmlNode); while(!nodeStack.isEmpty()) { node = nodeStack.pop(); htmlNode = htmlStack.pop(); //判断是否是叶节点 if(node.children) { for(var i = 0 ; i < node.children.length ; i++) { nodeStack.push(node.children[i]); //判断是否为叶节点 if(node.children[i].children) isleaf = false; else isleaf = true; //判断是否为当前子节点集的最后一个节点 var isLast = false; if(i == node.children.length-1) { isLast = true; } //创建子节点 var tempNode = this.createNode({ text: node.children[i].name, data: node.children[i].data, parent: htmlNode, isLeaf: isleaf, isLastNode: isLast }); htmlStack.push(tempNode); } } } if(this._showRoot) { dom.getElementById(this._renderTo).appendChild(htmlRootNode); } dom.getElementById(this._renderTo).appendChild(htmlRootNode.childrenbox); //设置根节点 this._htmlRootNode = htmlRootNode; } } w.JsTree = Tree; } (window));
以上是javascript tree核心库, 下面是调用方式
//数据格式 var jsonTree = [{ name: 'ROOT根节点', data: '用户数据' children: [ {name: 'java'}, {name: 'object-c'}, {name: 'javascript'} ] }]; var tree = new JsTree({ treedata: jsonTree, renderTo: 'treebox', showRoot: false }); //添加节点单击事件 tree.addClickEvt(function(o) { alert(o); }); // 展开 tree.expand(); // 收缩 tree.shrink();
目标只实现了三个接口,添加单机事件,展开,收缩... 最后来一个列子吧