xtree.js

来自「JS-异步加载树」· JavaScript 代码 · 共 1,427 行 · 第 1/3 页

JS
1,427
字号
/**
XTree类库使用帮助

版权申明:

	此程序是蓝翼(蓝色街灯)在http://webfx.eae.net 提供的XTree的基础上,重新设计实现的,因为程序的大致思路是采纳Erik的设计,因此在转载和重新修改的时候请保留webfx为原作者,蓝色街灯为此程序的作者。


作者:
	liuruhong(蓝翼,蓝色街灯)
编写时间:

	2003年8月20日

最后修改时间

	2003年11月2日

修改申明:

	可以随意转载和修改我的代码,但是希望能够保留住如上的申明,如果修改过代码,麻烦给我发送到我的email
联系方式:

	mailto:liuruhong@263.net
-----------------------------------------------------------------------------
Api使用帮助

//////////////////////
//1.参数配置
//////////////////////
变量:

	treeConfig
说明:

	树的一些基本设置,如图片的位置,css样式等等

详细参数:

	rootIcon:顶级接点图标
	openRootIcon:顶级节点展开时候的图标
	folderIcon:有子节点的节点图标

	openFolderIcon:有子节点节点展开时候的图标
	fileIcon:末节点图标

	iIcon:I型线
	lIcon:L型线
	lMinusIcon:L型收缩时候图标

	lPlusIcon:L型展开时图标

	tIcon:T型线
	tMinusIcon:T型收缩图标

	tPlusIcon:T型展开图标
	blankIcon:空图标

	
	defaultText:创建TreeItem时默认文字


	allowDrag:Tree节点是否支持拖动(是否触发onDrag事件),默认不触发
	
	css_ItemText:正常节点的样式

	css_ItemTextHover:鼠标移入时节点样式

	css_ItemTextSelected:节点选中时候的样式
	css_ItemTextSelectedNoFocus:节点选中但是焦点不再时候的样式
	
	css_ItemContainer:下级节点容器样式
	css_ItemTextContainer:节点所在行容器的样式

	注:建议不要修改这两个


	css_ItemCheckBox:在TreeCheckItem里头复选框的样式

	css_ItemDragTooltip:拖动的提示样式

	css_ItemDragingOver:节点拖动的时候经过的节点显示的样式


	
变量:
	treeHandler
说明:

	包含一些处理方法处理的实现函数,主要是完成dom 到JavaScript Object的映射,本来打算写一个singleton,不过想想还是使用变量简单

详细参数:

	idCount:递增,记录节点数
	idPrefix:HTML中id命名的前缀
	getId:获取节点ID(用于编程控制的)
	toggle:切换node的状态(展开或者收缩)
	hover:处理鼠标移动到节点

	restore:处理还原节点状态

	select:处理选择节点
	focus:处理节点或者焦点

	keycode:处理键盘事件
	mousedown:处理鼠标按下
	mousemove:处理鼠标移动
	mouseup:处理释放鼠标
	contextmenu:处理节点右键
	blur:处理节点失去焦点
	all:存储所有创建的节点
	selected:记录选择的节点


注:作为二次开发人员,完全可以不关心treeHanlder的内容,这里的说明只是为了帮助更好的理解我的处理模型

////////////////////////////////////////
//2.TreeItem
///////////////////////////////////////
说明:

	这个是最重要的实现类,也是其他类继承实现的基础,里头提供的一些方法是内部调用的,在这里我只是提供对于二次开发人员经常需要使用到的一些方法和事件,有兴趣的可以通读代码之后自己研究,或者写信和我一起探讨


详细介绍

方法
	toString():覆盖object的默认方法,同时产生需要的html代码
	add 添加子节点

		参数oItem为TreeItem的事例或者继承类的实例

	remove 删除节点本身
	setCaption修改节点标题
	rerender:重新产生HTML,对于开发人员而言,不要去调用,如果是扩展接口,必要的情况下可以调用

	unselect:不选择单前节点
	select:选择当前节点
	blur:让其失去焦点
	_root:取得顶级节点

	toggle:切换节点状态

	expand:展开节点
	collapse:收缩节点
	collapseAll:全部收缩
	collapseChildren:收缩当前节点的全部子节点
	expandAll:展开所有子节点
	expandChildRen:展开当前节点的子节点
	getFirst:取得第一个子节点
	getLast:取得当前节点递延的最后一个节点

	getPreviousSibling:取得前一个节点

	getNextSibling:取得后一个节点


属性

	Text:节点文本
	Action:节点行为
	target:联接框架
	OpenImage:节点图标
	parent:上级节点
	Nodes:子节点数组

	id:节点id
	_last:是否是父级节点的最后一个节点

	rendered:HTML是否已经生成



//////////////////////////////////
//3.TreeObject
/////////////////////////////////
说明;

	Tree的主节点对象,创建一个tree,必须从这个对象开始创建

详细说明:

	继承了TreeItem的所有方法

	
	扩展方法如下:

	write:输出html,这个是每个tree初始化必要的调用
	selected:获取tree被选中的节点


事件
	onSelected(oNode):选中节点
	onUnSelected(oNode):不选中节点
	onExpand(oNode):展开节点
	onCollapse(oNode):收缩节点

	onDrag(fromNode,toNode):拖动节点

	这里的oNode都是JavaScript的TreeItem或者继承的实例
///////////////////////////////////////
//4。TreeCheckItem
///////////////////////////////////////
说明:

	带有复选框的节点实现

详细说明:

	继承所有TreeItem的方法

	扩展方法

	toString()这个方法重新写了,如果有兴趣的,可以调用看看具体的html
	check:可以切换选择状态,true代码选中,false表示非选中

	如果实现了TreeCheckItem,这个时候通过你的obj._root()得到顶级节点之后,可以调用etSelectedNodes,这样可以得到一个被选中的TreeCheckItem的数组


注:这里我还没有提供oncheck这个事件,日后会考虑加入,另外对于treeItem还没有去考虑不是全部选中子节点的界面表现,就是说只是实现了两个状态,应该有3个状态的

////////////////////////////
//5。TreeXLoadItem
///////////////////////////
说明:

	通过xml源提供异步加载数据的能力
详细说明:

	没有提供特殊的方法,就是创建的时候参数不同

注:
	我还没有做到很好的和TreeCheckItem的结合,通过多个线程的情况下有些问题,还有可以考虑增加reload的方法


////////////////////////////
//其它说明
///////////////////////////

TreeItem.getXML,提供了将JS Nodes序列化成xml的接口,不过还没有提供加载的功能

我个人目前认为还需要改善的有如下:
1。支持节点图标的自定义

2。修改事件接口,最好能够使用命令模式,即addListener的方式

3。修改XLoadItem的实现,最好分离出DataSource,支持多种数据格式的加载
4。修正一些运行状态的bug
5。在IE5和Netscape下面调试通过



至于长远的打算

1.重新修改底层的实现,载接口设计方面尽量的完善
2.使用asp.net编写成Web Control
3.使用Java实现TagLib


如果对于这个方面有兴趣的朋友,可以和我联系,一起讨论liuruhong@263.net



*/

/*
*更新进度
*2003年9月1日 Version 0.5
*完成基础框架功能
*
*2003年11月3日 Version 0.51
*修正了Css及其代码实现中不是很流畅的部分

*
*2003年12月10日 Version 0.55
*添加了部分工具类代码,如数组的操作,字符串的操作
*
*2003年12月18日 Version 0.6
*实现节点的自定义图标
*/




/////////////////////////////////////////////////////////////////////////
//以下代码实现公共一些对象的基本操作
//////////////////////////////////////////////////////////////////////////

Array.prototype.indexOf=function(o)
{
        for(var i=0;i<this.length;i++)
        {
                if(this[i]==o)
                return i;
        }
        return-1;
};
Array.prototype.lastIndexOf=function(o)
{
        for(var i=this.length-1;i>=0;i--)
        {
                if(this[i]==o)
                return i;
        }
        return-1;
};
Array.prototype.contains=function(o)
{
        return this.indexOf(o)!= -1;
};
Array.prototype.copy=function(o)
{
        return this.concat();
};
Array.prototype.insertAt=function(o,i)
{
        this.splice(i,0,o);
};
Array.prototype.insertBefore=function(o,o2)
{
        var i=this.indexOf(o2);
        if(i== -1)
        this.push(o);
        else this.splice(i,0,o);
};
Array.prototype.removeAt=function(i)
{
        this.splice(i,1);
};
Array.prototype.remove=function(o)
{
        var i=this.indexOf(o);
        if(i!= -1)
        this.splice(i,1);
};
String.prototype.trim=function()
{
        return this.replace(/(^\s+)|\s+$/g,"");
};
//////////////////////////////////////////////////////////////////////
//为Object添加Clone的方法,因为所有的对象的顶级对象都是Object
//因此所有用户自定义对象都实现了Clone的方法

//////////////////////////////////////////////////////////////////////
Object.prototype.Clone=function(){
	function CloneModel(){
		
	}
	CloneModel.prototype=this;
	var objClone=new  CloneModel();
	
	var strMsg="";
	for( v in objClone){	
		switch (typeof objClone[v]){
			case "function": 
				//如果是方法,不需要进行clone
				objClone[v]=objClone[v];
				break;
			case "object": 
			///////////////////////////////////////////////////////////////////////
			//如果是对象,采用Clone重新得到,这样做的目的在于能够进行深度Clone
			//因为JavaScript是一个Object Based的语言,不然内部对象是指向原来的引用

			///////////////////////////////////////////////////////////////////////
				objClone[v]=objClone[v].Clone();
				break;
			default: 
			///////////////////////////////////////////////////////////////////////
			//其余数据类型情况下全部重新赋值

			//这样做的目的就是保证数值在内存中的存放是在新对象的空间中

			//而不仅仅指向Parent Object的一个refrence
			///////////////////////////////////////////////////////////////////////
				objClone[v]=objClone[v];
		}			
	}
	return objClone;
}


///////////////////////////////////////////////////////
//tree的基本配置

///////////////////////////////////////////////////////

var treeConfig={
	rootIcon        : '../src/tree/images/xp/folder.png',
	openRootIcon    : '../src/tree/images/xp/openfolder.png',
	folderIcon      : '../src/tree/images/xp/foldericon.png',
	openFolderIcon  : '../src/tree/images/xp/openfoldericon.png',
	fileIcon        : '../src/tree/images/xp/foldericon.png',
	iIcon           : '../src/tree/images/I.png',
	lIcon           : '../src/tree/images/L.png',
	lMinusIcon      : '../src/tree/images/Lminus.png',
	lPlusIcon       : '../src/tree/images/xp/Lplus.png',
	tIcon           : '../src/tree/images/T.png',
	tMinusIcon      : '../src/tree/images/Tminus.png',
	tPlusIcon       : '../src/tree/images/Tplus.png',
	blankIcon       : '../src/tree/images/blank.png',
	defaultText     : 'Tree Item',
	allowDrag       : false, ///是否允许拖动
	
	css_ItemText    : 'tree-text-item',
	css_ItemTextHover: 'tree-text-item-hover',
	css_ItemTextSelected: 'tree-text-item-selected',
	css_ItemTextSelectedNofocus:'tree-text-item-selected-nofocus',
	css_ItemTextContainer:'tree-text-container',
	css_ItemContainer:'tree-container',
	css_ItemCheckBox:'tree-text-item-checkbox',
	css_ItemDragTooltip:'tree-item-dragingTooltip',
	css_ItemDragingOver:'tree-item-dragingOver'
	
}
///////////////////////////////////////////////////////////////////
//tree逻辑操作模型和DHTML的映射

///////////////////////////////////////////////////////////////////
var treeHandler={
	idCounter :0,
	idPrefix  :"web-tree-",
	getId     : function() { return this.idPrefix + this.idCounter++; },
	toggle    : function(oItem){ this.all[oItem.id.replace("-plus","")].toggle() },
	hover     : function(oItem){ this.all[oItem.id.replace("-text-anchor","")].hover()},
	restore   : function(oItem){ this.all[oItem.id.replace("-text-anchor","")].restore()},
	select    : function(oItem){ this.all[oItem.id.replace("-text-anchor","")].select()},
	focus     : function(oItem){ this.all[oItem.id.replace("-text-anchor","")].select()},
	keycode   : function(oItem,e){ this.all[oItem.id.replace("-text-anchor","")].keycode(e.keyCode)},
	mousedown : function(oItem,e){ this.all[oItem.id.replace("-text-anchor","")].startDrag(e)},
	mousemove : function(oItem,e){ this.all[oItem.id.replace("-text-anchor","")].Draging(e)},
	mouseup   : function(oItem,e){ this.all[oItem.id.replace("-text-anchor","")].endDrag(e)},
	contextmenu: function(oItem,e){this.all[oItem.id.replace("-text-anchor","")].contextmenu(e)},
	blur      :function(oItem){ this.all[oItem.id.replace("-text-anchor","")].blur()},	
	all:{ },
	selected:null
};
///////////////////////////////////////////////
//预先加载图片
//////////////////////////////////////////////

function Tree_preloadImages()
{
  if(document.images)
  {
    if(!document.imageArray) document.imageArray = new Array();
    var i,j = document.imageArray.length, args = Tree_preloadImages.arguments;
    
    for(i=0; i<args.length; i++)
    {
      if (args[i].indexOf("#")!=0)
      {
        document.imageArray[j] = new Image;
        document.imageArray[j++].src = args[i];
      }
    }
  }
}

Tree_preloadImages(treeConfig.rootIcon,treeConfig.openRootIcon,treeConfig.folderIcon,treeConfig.openFolderIcon,treeConfig.fileIcon,treeConfig.iIcon,treeConfig.lIcon,treeConfig.lMinusIcon,treeConfig.lPlusIcon,treeConfig.tIcon,treeConfig.tMinusIcon,treeConfig.tPlusIcon,treeConfig.blankIcon);


//////////////////////////////////////////////////////////////
//如下代码实现事件处理回调的借口,如同Java语言中Listener
//////////////////////////////////////////////////////////////

function EventTarget(){
	this._listeners={
	};	
}
var _p=EventTarget.prototype;

//添加事件处理
_p.attachEvent=function(eType,eHandler,eObject){

};

//取消事件处理
_p.detachEvent=function(eType,eHandler,eObject){

};

//执行事件处理
_p.dispatchEvent=function(){
	
};
//释放对象
_p.Dispose=function(){

}

function EventObject(){

}


function TreeItem(sText,sAction,sTarget,sIcon,sOpenImage){
	this.Text=sText;
	this.Action=sAction;
	this.target=sTarget;
	this.OpenImage=sOpenImage;
	this.Image=sIcon;
	this.Nodes=new Array();	
	this.level=0;
	this.parent=null;
	this.id=treeHandler.getId();
	this._last=false;
	this.rendered=false;//是否显示]	
	treeHandler.all[this.id]=this;
	this.open=false;
	
}
///////////////////////////////////////////////////////////////////
//toString()采用DHTML DOM实现,在考虑到多个平台运行的情况下

//可以使用字符串拼接的方法来重新实现

///////////////////////////////////////////////////////////////////
TreeItem.prototype.toString=function(){
	var divText=document.createElement("div");
	divText.className=treeConfig.css_ItemTextContainer;
	divText.nowrap=true;
	divText.onselectstart="return false";
	divText.ondragstart="return false";
	divText.oncontextmenu="return false";	
	divText.ondblclick="treeHandler.toggle(this)";
	divText.id=this.id ;		
	
	var divContainer=document.createElement("div");	
	divContainer.onselectstart="return false";
	divContainer.ondragstart="return false";
	divContainer.oncontextmenu="return false";
	divContainer.id=this.id +"-container";
	
	divContainer.className=treeConfig.css_ItemContainer;
	
	divContainer.id=this.id +"-container";
	if (this.level ==0){ //顶层处理
		var img=document.createElement("img");
		img.src=treeConfig.rootIcon;
		divText.appendChild(img);		
	}
	else{
		//for(var i=0;i<(this.level -1);i++){
		var foo=this.parent;
		while(foo.parent){			
			var img=document.createElement("img");
			img.align="absmiddle";			
			if(foo._last==true){
				img.src=treeConfig.blankIcon;
			}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?