锁定老帖子 主题:JSTree for AJAX
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-06-27
目标: 1、高性能,假如树上有成千上万的节点,展示的速度应该不会考验用户的耐心 2、使用方便,允许这个对象的使用者能很方便根据对象接口来展示树型数据、向它增加节点、删除节点、展开和收缩节点、获取当前选中节点以及节点上的依附对象、选择和取消选择节点 3、跨平台,至少能够在IE以及firefox上运行。 为了实现这个目标,我提供了2个js对象:Tree和Node,还有一个超类:SkyObject。代码如下: function SkyObject(){ var id = 0; var className = "SkyObject"; this.getId = function(){ return id; } this.setId = function(_id){ id = _id; } this.setClassName = function(name){ className = name; } this.getClassName = function(){ return className } addToContainer(this); this.getElement = function(){ return window.document.getElementById("obj_"+ this.getId()); } } var hxdObjPointer = 0; var hxdContainer = []; function addToContainer(obj){ obj.setId(hxdObjPointer); hxdContainer[hxdObjPointer] = obj; hxdObjPointer++; } function getFromContainer(id){ return hxdContainer[id]; } function stateClick(id){ var node = getFromContainer(id); node.changeState(); } function nodeClick(id){ var node = getFromContainer(id); node.onSelected(); var root = node.getRoot(); var preNodeId = root.getPreNodeId(); var preNode = getFromContainer(preNodeId); if(preNode!=null) preNode.onUnSelected(); } function Node(data,parentNode){ SkyObject.call(this); var pNode = parentNode; var value = data; var state = "closed"; var children = []; this.setClassName("Node"); var childrenInited = false; this.getRoot = function(){ var current = this; var parent = null; while(true){ try{ parent = current.getParentNode(); }catch(e){ } if(parent==null || parent=="undefined"){ return current; }else{ current = parent; parent = null; } } } this.getParentNode = function() { return pNode; } this.getValue = function(){ return value; } this.onSelected = function(){ var element = window.document.getElementById("namelink_"+this.getId()); element.style.color="blue"; var root = this.getRoot(); root.setCurrentNodeId(this.getId()); root.onNodeChange(); } this.onUnSelected = function(){ var element = window.document.getElementById("namelink_"+this.getId()); if(element!=null) element.style.color="black"; if(this.getId()==root.getCurrentNodeId()){ var root = this.getRoot(); root.setCurrentNodeId(-1); } } this.removeChild = function(node){ if(node==null || node=="undefined") return; var newChildren = []; var index = 0; for(var i=0;i<children.length;i++){ var child = children[i]; if(node.getId()!=child.getId()){ newChildren[index] = child; index++; } } delete children; children = newChildren; var element = window.document.getElementById("children_"+this.getId()); if(element!=null){ if(children.length>0) element.removeChild(node.getElement()); else this.getElement().removeChild(element); } this.repaint(); } this.addChild = function(node){ children[children.length] = node; var element = window.document.getElementById("children_"+this.getId()); if(element==null){ if(value.children!=null && value.children.length>0){ this.paintChildren(); element = window.document.getElementById("children_"+this.getId()); } element = window.document.createElement("div"); element.id="children_"+this.getId(); this.getElement().appendChild(element); } state="opened"; element.style.display = "block"; node.paint(element); this.repaint(); } this.changeState = function(){ var stateLink = window.document.getElementById("statelink_"+this.getId()); if(state=="opened"){ stateLink.innerHTML=" + "; state="closed"; }else{ state="opened"; stateLink.innerHTML=" - "; } var childrenElement = window.document.getElementById("children_"+this.getId()); if(childrenElement==null){ if(state=="opened") this.paintChildren(); }else{ if(state=="opened"){ childrenElement.style.display = "block"; }else{ childrenElement.style.display = "none"; } } } this.paintChildren = function(){ childrenInited = true; var nodeElement = this.getElement(); var childrenElement = null; if(value.children!=null && value.children.length>0){ childrenElement = window.document.createElement("div"); childrenElement.id="children_"+this.getId(); for(var i=0;i < value.children.length;i++){ var childNode = new Node(value.children[i],this); children[i]=childNode; childNode.paint(childrenElement); } childrenElement.style.display = "block"; nodeElement.appendChild(childrenElement); } } this.repaint = function(){ var statelink = document.getElementById("statelink_"+this.getId()); var namelink = document.getElementById("namelink_"+this.getId()); if(children!=null && children.length>0){ if(state=="opened"){ statelink.innerHTML=" - "; }else{ statelink.innerHTML=" + "; } statelink.href='javascript:stateClick(' + this.getId() +')'; }else{ statelink.innerHTML=" . "; } namelink.innerHTML = value.name; } this.paint = function(parent){ var nodeElement = window.document.createElement("div"); nodeElement.style.position = "relative"; nodeElement.id = "obj_"+ this.getId(); var statelink = window.document.createElement("a"); statelink.id = "statelink_"+this.getId(); if(value.children!=null && value.children.length>0){ if(state=="opened"){ statelink.innerHTML=" - "; }else{ statelink.innerHTML=" + "; } statelink.href='javascript:stateClick(' + this.getId() +')'; }else{ statelink.innerHTML=" . "; } nodeElement.appendChild(statelink); var namelink = window.document.createElement("a"); namelink.id = "namelink_" + this.getId(); namelink.href='javascript:nodeClick(' + this.getId() + ')'; namelink.innerHTML = value.name; nodeElement.appendChild(namelink); if(state=="opened"){ paintChildren(); } if(parent.type=="nodesPane") nodeElement.style.left = 2; else nodeElement.style.left = 20; parent.appendChild(nodeElement); } } function Tree(){ SkyObject.call(this); var children = []; var title = "title"; var element = null; var parent = null; var value = null; var currentNodeId = -1; var preNodeId = -1; this.setCurrentNodeId = function(id){ preNodeId = currentNodeId; currentNodeId = id; } this.getPreNodeId = function(){ return preNodeId; } this.getCurrentNodeId = function(){ return currentNodeId; } this.getCurrentNode = function(){ if(currentNodeId<0){ return null; }else return getFromContainer(currentNodeId); } this.onNodeChange = function(){}; this.bindData = function(data){ value = data; } this.addChild = function(data){ var node = new Node(data,this); children[children.length] = node; var treeElement = this.getElement(); node.paint(treeElement); } this.addChildToSelectedNode = function(data){ var selectednode = this.getCurrentNode(); var node = new Node(data,selectednode); selectednode.addChild(node); } this.removeChild = function(node){ var parent = node.getParentNode(); if(parent.getId()==this.getId()){ var element = this.getElement(); element.removeChild(node.getElement()); var newChildren = []; var index = 0; for(var i=0;i<children.length;i++){ var child = children[i]; if(node.getId()!=child.getId()){ newChildren[index] = child; index++; } } delete children; children = newChildren; }else{ parent.removeChild(node); } } this.getElement = function(){ var nodesPane = window.document.getElementById("obj_"+ this.getId()) if(nodesPane==null){ nodesPane = window.document.createElement("div"); nodesPane.id = "obj_"+this.getId(); nodesPane.type = "nodesPane"; if(value!=null && value.length>0){ for(var i=0;i<value.length;i++){ var node = new Node(value[i],this); children[i] = node; node.paint(nodesPane); } } } return nodesPane; } this.paint = function(parent){ var nodesPane = window.document.createElement("div"); nodesPane.id = "obj_"+this.getId(); if(value!=null && value.length>0){ for(var i=0;i<value.length;i++){ var node = new Node(value[i],this); children[i] = node; node.paint(nodesPane); } } parent.appendChild(nodesPane); } } 源代码的确有点长,幸好,对开发者来说,他们不必要了解其中的细节。他们只需要知道有来写方法可用就行了。下面的代码是操纵这个组件的示例: <script type="text/javascript" src="SigmaTree.js"></script> <script language="javascript"> var tree1 = null; var tree2 = null; window.onload = function(){ var roots = {tree:[ {id:"1",name:"name1",children: [ {id:"10",name:"child0",children:[]}, {id:"11",name:"child1",children:[]}, {id:"12",name:"child2",children:[]}, {id:"13",name:"child3",children:[]}, {id:"14",name:"child4",children:[]} ] }, {id:"2",name:"name2",children:[]}, {id:"3",name:"name3",children:[]} {id:"4",name:"name4",children:[]}, ]}; var parent1 = document.getElementById("tree1"); tree1 = new Tree(); tree1.bindData(roots.tree); tree1.paint(parent1); tree1.onNodeChange = function(){ } var parent2 = document.getElementById("tree2"); tree2 = new Tree(); tree2.bindData(roots.tree); tree2.paint(parent2); tree2.onNodeChange = function(){ } } function addNew(){ var nodedata = {id:"123",name:"newNode123"}; tree1.addChild(nodedata); } function addNewToSelected(){ var nodedata = {id:"123",name:"newNode123"}; tree1.addChildToSelectedNode(nodedata); } function removeSelectedNode(){ var node = tree1.getCurrentNode(); tree1.removeChild(node); } </script> 效果: 1、出色的性能:假如树上节点分布比较均匀的话,该组件可以轻松在1秒内载入上万个节点。所谓分布均匀,指的是每个节点的子节点的数量大致相等,比如,顶层节点有100个,每个节点又有100个子节点,那么总共有10000个节点。由于该组件只绘制需要展示的节点,因此刚启动的时候仅仅绘制了100个顶层节点,所以具有很高的性能。 2、良好的用户体验:页面可以在不刷新的情况下操纵这棵树,比如:删除节点、增加节点、展开和收缩节点。 3、良好的编程体验:程序员可以通过bindData() 来绑定一棵js对象组成的树,并在一个指定的div或者别的什么元素中绘制出这棵树,向树增加和删除节点是非常方便的。编程的便利和普通c/s ide提供的控件相比不遑多让。如果需要把对树的操纵持久化到服务器上,程序员可以通过xmlhttp来实现。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2005-07-05
收藏,你有解决修改css的问题么?
比如下面这样还是比较麻烦的,我看qooxdoo之类的都是在js控件里预先设置好的 var jsTable = new JSTable(items);; jsTable.setWidth('100%');; //jsTable.setCellspacing(1);; jsTable.setClass('tableborder');; jsTable.setAllRowBgColor('#F8F8F8');; |
|
返回顶楼 | |
发表时间:2005-07-06
alin_ass 写道 收藏,你有解决修改css的问题么?
没怎么关注过这个问题 |
|
返回顶楼 | |
发表时间:2005-07-21
不错,实例中少了一个逗号
{id:"2",name:"name2",children:[]}, {id:"3",name:"name3",children:[]}, {id:"4",name:"name4",children:[]}, 再加两个div就可以运行了: <body> <div id="tree1"></div> <div id="tree2"></div> </body> 加一个排序的功能如何? |
|
返回顶楼 | |
发表时间:2005-07-22
z_jordon 写道 不错,实例中少了一个逗号
{id:"2",name:"name2",children:[]}, {id:"3",name:"name3",children:[]}, {id:"4",name:"name4",children:[]}, 再加两个div就可以运行了: <body> <div id="tree1"></div> <div id="tree2"></div> </body> 加一个排序的功能如何? 谢谢了! 在树上实现排序功能,有这个必要么? |
|
返回顶楼 | |
发表时间:2005-07-23
比如说用在部门组织上,用户对于哪个部门在前,哪个部门在后非常在意的话。
|
|
返回顶楼 | |
发表时间:2005-07-25
真想知道大家是怎么样做排序的
|
|
返回顶楼 | |
发表时间:2005-07-26
z_jordon 写道 比如说用在部门组织上,用户对于哪个部门在前,哪个部门在后非常在意的话。
假如只按照一种规则排序,那么可以在服务器端排序,没有必要在客户端做。在客户端也可以的,你在网上找找看对Array进行排序的js代码,我手边没有 |
|
返回顶楼 | |
发表时间:2005-08-02
z_jordon 写道 不错,实例中少了一个逗号
{id:"2",name:"name2",children:[]}, {id:"3",name:"name3",children:[]}, {id:"4",name:"name4",children:[]}, 再加两个div就可以运行了: <body> <div id="tree1"></div> <div id="tree2"></div> </body> 加一个排序的功能如何? 我把上部的代码保存为SigmaTree.js 运行时出现脚本错误:value.children对像找不着。 我觉得这个也很不错 http://www.destroydrop.com/javascripts/tree/ 在网上有个例子配合struts的标签。 |
|
返回顶楼 | |
发表时间:2005-08-02
那这个也不错:
http://webfx.eae.net/dhtml/xtree/index.html struts的标签真是越用越不爽,而且如果现在用Buffalo来做做开发的话,用js和service层直接打交道,不需要struts,webwork了. |
|
返回顶楼 | |