一个纯js实现树

共两个文件
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);	






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值