共两个文件
1:main.def.js: 树数据结构定义
2: main.imp.js: 一些基本的树生成实现(包括树形SELECT, 标准文件夹结构树[可折叠,可添加点击动作])
main.Impl.js中的图片自己去找,图片文件名可以不一样,不要修改前面的NAMES
BOTTOM:"<IMG src=imgs/WindowsExplorer/nodeBottom.gif>"
适用:IE8 FireFox3.6.X
节点数目:在一个节点下不能超过150个子节点,但是分开在不同节点的话,测试超过600个以上折叠展开2s之内
/*****************************************************************
* 文件名 TreeContext.def.js
* 创建时间 2010-6-20 12:19PM
* 创建人 victor.woo@163.net
* 说明 Js Tree 数据结构定义
* 用法: 调用者自身保证数据的合理性,比如ID不能重复
本js只做基本的检查
******************************************************************/
/*
TreeNode Data input form
var Earth = {
id: "Earth"
, pid:"Sun"
, diameter:"7920 miles"
, distance:"93 million miles"
, year:"365.25"
, day:"24 hours"
};
*/
function JsTreeNode(data)
{
this.nodeData = data;
this.id = data.id;
this.pid = data.pid;
this.open =data.open;
this.level = 0;
this.degree = 0;
this.ownerTree = null;
this.parentNode = null;
this.ancestorFlag = null;
this.leftSibling = null;
this.rightSibling = null;
this.childNodes = null;
this.firstChild = null;
this.lastChild = null;
if(this.open=="yes"){
this.bCollapsed = false;
}else{
this.bCollapsed = true;
}
this.bIterated = false;
//构造函数
this.init= function()
{
}.call();
this.isRoot = function() { return this.parentNode==null; }
this.isLeaf = function() { return this.degree==0; }
this.isYoungest = function() { return this.rightSibling==null; }
this.switchCollapse=function() { this.bCollapsed = !this.bCollapsed;
}
this.collapse= function(b) { this.bCollapsed = b; }
this.belongFamily= function(s) { return this.ancestorFlag.indexOf(s)==0; }
this.removeChild = function(n) {}
this.getNode=function(nid)
{
if(!this.childNodes)
return null;
for(var i=0;i<this.childNodes.length;i++){
if(this.childNodes[i].id==nid)
return this.childNodes[i];
}
return null;
}
this.appendChild=function(childNode)
{
if(this.getNode(childNode.id)!=null){
alert("repeat child: ID="+id);
return false;
}
if(this.childNodes==null){
this.childNodes = new Array();
this.firstChild = childNode;
}
this.childNodes.push(childNode);
this.degree++;
childNode.parentNode = this;
childNode.leftSibling = this.lastChild;
if(this.lastChild)
this.lastChild.rightSibling = childNode;
this.lastChild = childNode;
return true;
}
this._next_LEFTFIRST = function() //左序优先遍历,深度优先 ,文件夹结构
{
if(this.isRoot()&&this.bCollapsed)
return null;
if(!this.isLeaf()&&!this.bCollapsed) //有子节点
return this.childNodes[0];
//没有子节点或者子节点被折叠了,都到下一个兄弟节点
if(this.rightSibling) //找到下一个子节点
return this.rightSibling;
//遍历返回父节点,直到在某层找到一个兄弟节点
var pNode = this.parentNode;
while(!pNode.isRoot())
{
if(pNode.rightSibling) //找到父节点的下一个子节点
return pNode.rightSibling;
pNode = pNode.parentNode;
}
return null;
}
this._next_RIGHTFIRST = function() //右序优先遍历,广度优先,组织架构图
{
var treeLNL = this.ownerTree.getLayeredNodesList();
var sameLayerNodes = treeLNL[this.level];
var nodesCount = sameLayerNodes.length;
var _index = 0;
for(var i=0;i<sameLayerNodes.length;i++){
if(sameLayerNodes[i].id==this.id){
_index = i;
break;
}
}
_index++;
if(_index<nodesCount)
return sameLayerNodes[_index];
if(this.level+1==treeLNL.length)//最底层
return null;
return treeLNL[this.level+1][0];
}
}
function JsTree(treeid,rootNodeId)
{
var ownedNodes = new Array();
var id = null;
var depth = 0;
var degree = 0;
var rootID = null;
var root = null;
var LayeredNodesList= new Array();
var created = false;
this.getLayeredNodesList = function() { return LayeredNodesList; }
this.getRoot=function() { return root; }
this.hashCode = function() { return this._SUPER.hashCode(); }
this.getClass = function() { return this._SUPER.getClass(); }
//构造函数
this.init= function()
{
id = treeid ;
rootID = rootNodeId;
}.call();
this.addNode = function(newNode)
{
ownedNodes.push(newNode);
newNode.ownerTree = this;
}
this.setNodes = function(newNodes)
{
ownedNodes=newNodes;
for(var i=0;i<ownedNodes.length;i++)
ownedNodes[i].ownerTree = this;
}
this.resetNodes = function()
{
for(var i=0;i<ownedNodes.length;i++)
ownedNodes[i].bIterated = false;
}
this.getNode=function(nid)
{
for(var i=0;i<ownedNodes.length;i++){
if(ownedNodes[i].id==nid)
return ownedNodes[i];
}
alert("Development ERROR, CANNOT GET TREENODE: ID="+nid);
return null;
}
this.collapseNode=function(id) { this.getNode(id).switchCollapse(); }
this.collaspeAll=function(status)
{
for(var i=0;i<ownedNodes.length;i++)
ownedNodes[i].collapse(status);
}
this.create=function()
{
if(created)
return; //只调用一次
created = true;
root = this.getNode(rootID);
if(root==null){
alert("root not found: ID="+rootID);
return;
}
for(var i=0;i<ownedNodes.length;i++){
var tn = ownedNodes[i];
if(tn.id==root.id)
continue;
var ptn = this.getNode(tn.pid);
if(ptn==null)
return;
ptn.appendChild(tn);
if(ptn.degree>degree)
degree = ptn.degree;
}
processNode(root);
depth++; //depth=max(node.level)+ 1
LayeredNodesList.push(new Array(root));
processLayeredNodesList(0,LayeredNodesList);
}
function processNode(node)
{
if(node.isRoot())
node.ancestorFlag = node.pid+"_"+node.id;
else{
node.ancestorFlag = node.parentNode.ancestorFlag+"_"+node.id;
node.level = node.parentNode.level+1;
}
if(depth<node.level)
depth=node.level;
if(node.isLeaf())
return;
for(var i=0;i<node.childNodes.length;i++){
processNode(node.childNodes[i])
}
}
function processLayeredNodesList(level,allLevel)
{
var newLevel = level+1;
var newLevelArray = new Array();
var preLevel = allLevel[level];
for(var i=0;i<preLevel.length;i++){
var node = preLevel[i];
if(node.isLeaf())
continue;
for(var j=0;j<node.childNodes.length;j++)
newLevelArray.push(node.childNodes[j]);
}
if(newLevelArray.length>0){
allLevel.push(newLevelArray);
processLayeredNodesList(newLevel,allLevel);
}
}
}
/*****************************************************************
* Copyright(c)
*
* 文件名 TreeViewImp.def.js
* 创建时间 2010-6-22 08:44AM
* 创建人 victor.woo@163.net
* 说明 Js Tree 遍历+算子封装 及相关
实现
* 用法: new JsTreeTraverse(aT,"nodeProcessor","_next_RIGHTFIRST").iterate();
******************************************************************/
//遍历器封装类
function JsTreeTraverse(aTree,np,_type)
{
var objTree = null;
var currentID = null;
var nodeProcessor = null;
var travelType = null;
var strResult = "";
this.getResult = function() { return strResult; }
//构造函数
this.init= function()
{
objTree = aTree;
currentID = aTree.getRoot().id;
nodeProcessor = np;
travelType = _type;
}.call();
function visit()
{
var node = objTree.getNode(currentID);
return eval(nodeProcessor+"(node)");
}
this.iterate=function()
{
do
{
strResult += visit();
var node = aTree.getNode(currentID);
node = eval("node."+travelType+"()");
if(node==null)
return true;
currentID = node.id;
}while(true);
return false;
}
}
//---------------------------Basic 树显示组件遍历执行算子基类
function TreeViewNodeProcessor()
{
this.init = function()
{
}.call();
this.getSelfLine0=function(imgs,aNode)//不显示折叠图片+-,不提供折叠操作
{
if(!aNode.isRoot()){
if(aNode.isYoungest())
return imgs.BOTTOM+imgs.NODE;
else
return imgs.MIDDLE+imgs.NODE;
}
return imgs.ROOT+imgs.NODE;
}
this.getSelfLine1=function(imgs,aNode)//显示折叠图片+-,不提供折叠动作
{
this.getSelfLine2(imgs,aNode,null,false)
;
}
this.getSelfLine2=function(imgs,aNode,actions,canCollapse)//显示折叠图片,提供折叠动作
{
var _link = "";
if(canCollapse)
_link = "<A href=# οnclick=javascript:"+actions.collapse+"("+aNode.id+")>";
if(!aNode.isRoot()){
var ret = "";
if(aNode.isYoungest()){
if(aNode.isLeaf())
ret += imgs.BOTTOM;
else if(aNode.bCollapsed)
ret += _link+imgs.ARROWBOTTOMCLOSED+(_link==""?"":"</A>");
else
ret += _link+imgs.ARROWBOTTOM+(_link==""?"":"</A>");
}else{
if(aNode.isLeaf())
ret += imgs.MIDDLE;
else if(aNode.bCollapsed)
ret += _link+imgs.ARROWMIDDLECLOSED+(_link==""?"":"</A>");
else
ret += _link+imgs.ARROWMIDDLE+(_link==""?"":"</A>");
}
if(aNode.isLeaf())
ret += imgs.LEAF;
else
ret += imgs.NODE;
return ret;
}
if(aNode.bCollapsed)
return _link+imgs.ROOTCLOSED+(_link==""?"":"</A>")+imgs.NODE;
else
return _link+imgs.ROOT+(_link==""?"":"</A>")+imgs.NODE;
}
this.getFrontLines=function(imgs,aNode)
{
if(aNode.isRoot()) return "";
if(aNode.parentNode.isRoot()) return imgs.EMPTY;
var ret ="";
pNode = aNode.parentNode;
while(!pNode.isRoot()){
if(pNode.isYoungest())
ret = imgs.EMPTY+ret;
else
ret = imgs.NULL+ret;
pNode = pNode.parentNode;
}
return imgs.EMPTY+ret;
}
this.printNode=function(aNode)
{
alert("请重载方法:this.printNode=function(aNode) ");
}
}
//--------------------------树形SELECT构造--------------------------
var SelectTreeNodeImgs = {
BOTTOM :"┗"
,MIDDLE :"┣"
,EMPTY :" "
,NULL :"┃"
,ROOT :"☆"
,NODE :"☉"
};
function TreeSelectNodeProcessor() //树状下拉列表视图算子
{
this._SUPER = new TreeViewNodeProcessor("TreeViewNodeProcessor:TreeSelectNodeProcessor");
this.init = function()
{
}.call();
this.printNode=function(aNode)
{
var line = this._SUPER.getFrontLines(SelectTreeNodeImgs,aNode)
+this._SUPER.getSelfLine0(SelectTreeNodeImgs,aNode);
return "<OPTION>"+line+aNode.nodeData.text+"</OPTION>";
}
}
var $TreeSelectNodeProcessor = new TreeSelectNodeProcessor();
function $outputTreeSelect(aTree,_misc)
{
var ret = "<SELECT "+_misc+">";
var tt = new JsTreeTraverse(aTree,"$TreeSelectNodeProcessor.printNode","_next_LEFTFIRST") ;
tt.iterate();
ret += tt.getResult();
ret += "</SELECT>";
return ret;
}
//--------------------------树形SELECT构造--------------------------
//--------------------------标准动态树(可折叠收起)结构构造,节点点击处理--------
var $WindowStyleTreeNodeImgs = {
BOTTOM :"<IMG src=data/images/WindowsExplorer/nodeBottom.gif>"
,MIDDLE :"<IMG src=data/images/WindowsExplorer/nodeMiddle.gif>"
,EMPTY :"<IMG src=data/images/WindowsExplorer/nodeEmpty.gif>"
,NULL :"<IMG src=data/images/WindowsExplorer/nodeNull.gif>"
,ROOT :"<IMG src=data/images/WindowsExplorer/root.gif>"
,ROOTCLOSED :"<IMG src=data/images/WindowsExplorer/rootClosed.gif>"
,ARROWBOTTOMCLOSED :"<IMG src=data/images/WindowsExplorer/arrowBottomClosed.gif>"
,ARROWBOTTOM :"<IMG src=data/images/WindowsExplorer/arrowBottom.gif>"
,ARROWMIDDLECLOSED :"<IMG src=data/images/WindowsExplorer/arrowMiddleClosed.gif>"
,ARROWMIDDLE :"<IMG src=data/images/WindowsExplorer/arrowMiddle.gif>"
//以上是结构显示图片 (竖线,展开,折叠)
//以下是节点内容前的图片 :文件夹?文件,可以替换
,CURRENTNODE :"<IMG src=data/images/WindowsExplorer/openFolder.gif>"
,NODE :"<IMG src=data/images/WindowsExplorer/folder.gif>"
,LEAF :"<IMG src=data/images/WindowsExplorer/leaf.gif>"
};
var $MyStyleTreeNodeImgs = {
BOTTOM :"<IMG src=data/images/standard/nodeBottom.gif>"
,MIDDLE :"<IMG src=data/images/standard/nodeMiddle.gif>"
,EMPTY :"<IMG src=data/images/standard/nodeEmpty.gif>"
,NULL :"<IMG src=data/images/standard/nodeNull.gif>"
,ROOT :"<IMG src=data/images/standard/root.gif>"
,ROOTCLOSED :"<IMG src=data/images/standard/rootClosed.gif>"
,ARROWBOTTOMCLOSED :"<IMG src=data/images/standard/arrowBottomClosed.gif>"
,ARROWBOTTOM :"<IMG src=data/images/standard/arrowBottom.gif>"
,ARROWMIDDLECLOSED :"<IMG src=data/images/standard/arrowMiddleClosed.gif>"
,ARROWMIDDLE :"<IMG src=data/images/standard/arrowMiddle.gif>"
//以上是结构显示图片 (竖线,展开,折叠)
//以下是节点内容前的图片 :文件夹?文件,可以替换
,CURRENTNODE :"<IMG src=data/images/standard/openFolder.gif>"
,NODE :"<IMG src=data/images/standard/folder.gif>"
,LEAF :"<IMG src=data/images/standard/leaf.gif>"
};
function StandardDynamicTreeNodeProcessor()
{
var ActionList = null;
var canClickNode = false;
var canCollapse = false;
var TreeNodeImgs = null;
this._SUPER = new TreeViewNodeProcessor("TreeViewNodeProcessor:StandardDynamicTreeNodeProcessor");
this.init = function()
{
}.call();
this.setActionList = function(al)
{
ActionList = al;
canClickNode = ActionList&&ActionList.nodeClicked&&ActionList.nodeClicked!="" ;
canCollapse = ActionList&&ActionList.collapse&&ActionList.collapse!="" ;
}
this.setTreeNodeImgs = function(ss)
{
TreeNodeImgs = ss;
}
this.printNode=function(aNode)
{
var line = this._SUPER.getFrontLines(TreeNodeImgs,aNode)
+this._SUPER.getSelfLine2(TreeNodeImgs,aNode,ActionList,canCollapse);
if(canClickNode)
return "<TR><TD>"+line+"<SPAN><A href=# οnclick=javascript:"+ActionList.nodeClicked+"("+aNode.id+")>"+aNode.nodeData.text+"</A></SPAN></TD></TR>";
else
return "<TR><TD>"+line+"<SPAN>"+aNode.nodeData.text+"</SPAN></TD></TR>";
}
}
var $StandardDynamicTreeNodeProcessor = new StandardDynamicTreeNodeProcessor();
//al :
//var aL = { collapse:"collapse",nodeClicked:"nodeClicked",nodeMouseOver:"nodeMouseOver" } ,可折叠并其它操作
//var al = null; 无折叠动作
//var aL = { collapse:"collapse" } 只可折叠,无Node点击动作
function $outputStandardTree(aTree,_misc,al,TreeNodeImgs)
{
$StandardDynamicTreeNodeProcessor.setActionList(al);
$StandardDynamicTreeNodeProcessor.setTreeNodeImgs(TreeNodeImgs);
var ret ="<TABLE "+_misc+">";
var tt = new JsTreeTraverse(aTree,"$StandardDynamicTreeNodeProcessor.printNode","_next_LEFTFIRST") ;
tt.iterate();
ret += tt.getResult();
ret += "</TABLE>";
return ret;
}
//--------------------------动态树(可折叠收起)结构构造,节点点击处理--------
aTree = new JsTree("TestTree-1","0");
aTree.addNode(new JsTreeNode({id: 0,pid:-1 ,text:"元史", open:"yes"}));
aTree.addNode(new JsTreeNode({id: 1,pid:0 ,text:"本紀"}));
aTree.addNode(new JsTreeNode({id: 2,pid:0 ,text:"志"}));
aTree.addNode(new JsTreeNode({id: 3,pid:0 ,text:"表"}));
aTree.addNode(new JsTreeNode({id: 4,pid:0 ,text:"列傳"}));
var actions = {collapse:"collapse",nodeClicked:"nodeClicked"};
aTree.create();
//document.getElementById("TREESELECT").innerhtmlL = $outputTreeSelect(aTree,"size=16");
document.getElementById("TREEVIEW").innerHTML = $outputStandardTree(aTree,"border=0 style='border-collapse:collapse;'",actions,$WindowStyleTreeNodeImgs);