阿赖目录树控件程序简介

之前我曾经使用ASP设计过生成目录树的程序,那就是Open Host系统的目录树,完成于2003年1月份,在此之前浏览过www.9499.net的朋友对此一定有印象。如今使用javascript设计的这个目录树控件程序方法上与ASP有很大的差别,可以说难度更大,使用上更具灵活性,它是目前功能最强使用最简便的目录树程序。关于这个目录树控的功能特性方面,以下几点值得一提:

一、引入了图片控件与目录树控件配合使用,大大提高了灵活性。这一点上主要参考了VB6的TreeView控件。

二、在控件程序中引入了事件处理机制,增强了功能,也大大提高了使用的灵活性。

三、提供了大量的对象接口和方法。

四、提供了多种添加目录树节点的方法,有add方法,addLink方法,以及独创的pathParse方法(用来解析路径列表,以最简单的代码快速的构造目录树)。

五、目录树样式不受限制,用户完全可以设计出风格各异,灵活多变的目录树来。

六、提供多种现成的目录树模板,用户不必再费心去设计目录树样式,只需选取喜欢的模板,添加树节点即可,多快好省!

七、控件程序可根据需要进行功能扩展,目前提供checkbox节点扩展程序(alai_tree_check.js)就是一个很好的范例。

I. 概述:

阿赖目录树控件程序完全采用面向对象的方法设计,整个程序封装一个函数alai_tree()里面,另外随目录树程序提供了一个图片列表imagelist控件(alai_imagelist())。使用阿赖目录树控件程序构建目录树一般遵循以下三个步骤:

一、建立imagelist实例对象,并向控件添加建目录树所需的图片;

二、新建一个目录树控件实例,将上述imagelist实例对象作为第一个参数传递;

三、调用目录树控件的各种对象、方法,添加节点,定义事件处理程序等。

当然我们有更便捷的方法,就是使用现有的目录树模板程序以更简化的步骤来构建目录树,关于模板程序搁后再谈。在建立目录树前我先来理解目录树控件的三个核心对象:

(1)目录树控件实例对象(tree),如下:

??? var tree=new alai_tree()

??? 这样就新建了一个树对象。

(2)根(root)对象:tree.root,可以看出它是tree的一个成员,它是没有外观表现的,用于构建目录树第一级的节点,是第一级节点的父对象(parent)。

(3)节点(node)对象,对应于目录树上的一个节点,如下:

 var node=tree.add(...) //添加节点,参数先省略不谈

 上面调用目录添加节点的方法,生成了一个新的节点对象:node

这三个对象各自拥有很多的成员对象(属性、方法和事件),具体请查看《目录树控件对象参考》。接下举个例子,来看看构键目录树的过程:

?

II. 示例程序:

var images=new alai_imagelist() //建立imagelist实例对象
images.path="images/" //图片路径
images.add("file.gif","default") //添加图片,第二个参数是键值(key)
images.add("folder") //添加图片,文件后缀".gif"省了,键值缺省取文件名:"folder"
images.add("html","link")? //添加html.gif,键值为link
var tree1=new alai_tree(images,16,divTree1) //注意参数divTree1是目录树放置的地方,

//网页上有这样的代码:



,生成的目录树就插到这里面了。

var root=tree.root
var n1=root.add("节点一","default","js","alert('节点一')")
//等效代码:var n1=tree1.add(root,"last","节点一","n1","","js","alert('节点一')")
/* 下面代码演示各种添加节点的方法 */
var n2=root.add("节点二","folder")
var n23=n2.add("2-3") //添加n2的子节点
var n22=tree1.add(n23,"prev","2-2","n22") //将节点n22添加到n23之前
var n20=tree1.add(n2,"first","2-0","n20","file",) //由于"first"参数,这个节点作为n2的第一个子节点
var n3=tree1.add(root,"last","节点三","folder")
var n31=n3.addLink("http://www.9499.net") //添加n2的子节点
var n32=tree1.add(n3,"last","www.9499.net","n32","page","url","http://www.9499.net") //添加n2的子节点
var colNode=tree.pathParse("/节点四/4-1;/节点四/4-2;/节点四/4-3;/节点五/")
var n4=root.addLink("http://www.9499.net","欢迎访问9499.NET")

 

III. 添加节点的方法:

在上面的示例中我们总共接触到了五种添加目录树节点的方法,先看它们的语法原型:

1.tree.add(toNode,relation,text,key,ico,exeCategory,exeArg)

2.root.add(text,ico,exeCategory,exeArg)

3.root.addLink(url,text,target,ico)

4.node.add(text,ico,exeCategory,exeArg)

5.node.addLink(url,text,target,ico)

6.tree.pathParse(path,pathSeparator,listSeparator)

方法1的功能最全面,涵盖了方法2-5,但部分参数我们很少用到,所以用的较多的还是方法2-5。root对象的add方法总是添加第一级的节点,节点node对象的add方法用于添加节点的子节点。addLink方法方便我们添加有网址链接的节点。pathParse方法可解释一个路径列表生成对应的树结构。各个参数的说明请看目录树控件对象参考。

?

IV. 节点关系:

??? 阿赖目录树控件程序对于树结构有一个明晰的逻辑表述,这一点表现在树节点对象的下面几种关系上:

 node.first -- 节点的第一个子节点,若无子节点则为null

 node.last -- 节点的最后一个子节点,若无子节点则为null

 node.next -- 节点下一个相邻的子节点,若node是该层上最后一个结点则为null

 node.prev -- 节点上一个相邻的子节点,若node是该层上第一个结点则为null

 node.parent -- 节点的父节点

 node.chidren -- 节点的子节点(它是一个的集合数组,第个元素是一个节点对象)

对于根对象root:

root.first是第一级节点的第一个节点,root.last是第一级节点的最后一个节点,root.chidren是第一级节点的集合,第一级节点的parent等于root。

?

V. 节点对象的成员对象:

节点对象node包含了一些成员对象(属性),为了方便说明和理解,截了一张图放大后加上标注。如下:

数字所标示的对象依次为:

1.node.exIcon

2.node.icon

3.node.label

4.node.lineIcon[0]

5.node.body

6.node.container

 

VI. 访问节点对象:

1.从上面的示例中我们已经看到add方法会返回新添加的节点对象,将之赋予一个变量,以后随时可以访问。

2.所有添加的节点保存在tree.nodes集合数组中,如对于第一个添加的节点:

var n0=tree1.add(root,"last","节点一","node0")

  除了n0指向该节点外,tree.nodes[0]也指向该节点,另外我们还指定了一个键值:"node0",因此tree.nodes["node0"]也指向了该节点,因此n0、tree.nodes[0]和tree.nodes["node0"]引用的都是同一个对象。

3.执行目录树节点遍历的方法:可以从root.first开始根据节点关系可按多种方法进行遍历,在此不作深究。如果不关心树的逻辑结构进行遍历推荐的方法是:

for(var i=1;i<tree.count()-1;i++){tree.nodes[i]}

可能你会想到另一种方法:

for(var i=0;i<tree.nodes.length;i++){tree.nodes[i]}

也是可行的,但要注意如果有节点设了键值的话,该节点会被访问两次!

4.其它获得节点对象的方法:

??? (1)树对象的方法:getNodeByPath、getNodeByTier、getSelectNode、getActiveNode

??? (1)节点对象的方法: getSibling、节点关系(next,first,last,prev,parent,children)

VII. 节点的操作:

1.删除节点:node.remove() 或 tree.removeNode(node)

2.子节点的展开与收缩:

??? 展开:node.expand(true),收缩:node.expand(false),自动:node.expand()

??? 展开一个分枝(展开子节点孙子节点):node.expand(true,true)

??? 展开所有节点:tree.expandAll(true),收缩所有节点:tree.expandAll(false)

??? 展开至第二层:tree.expandToTier(2)

?

IX. imagelist控件与目录树控件的关系:

imagelist用于向目录树控件提供构建目录树的各种图片(图标),在目录树控件中这些图片是如何被使用的呢?在添加节点的方法中ico参数是用于设置节点图标的,如上例中n1节点ico为"default",这就是添加节点时指定的键值,除了用键值我们还可以用索引值,因为"default"是第一个添加的图标其索引值为0,用0来代替"default"也是可以的。可见目录树控件是通过键值(字符串)或索引值(正整数)来引用imagelist控件中的图片的。

我们还注意到有些节点添加时ico参数是缺省的,但是该节点还是有图标显示的,这就是要谈的另一个议题--约定键值。约定键值是指imagelist控件中具有这些键值的元素在目录树控件会有特殊的用途,约定键值有以下几种:

1、default -- 默认图标,在ico参数缺省时节点使用默认图标,图例:

2、expandcollapse -- 用于控制子节点展开和收缩,

  常用图例:

3、expand_topexpand_endcollapse_topcollapse_end,在使用上面第一组图例时提供首尾不同的图片

  图例:

4、leaftwig -- 用于指示树叶节点和末稍节点的图标,图例:

5、lineblank -- 用于画目录树支干连线。图例:(blank是一张空白的图片)

6、link -- 特别用于addLink方法,ico参数缺省时使用,图例:

按照这种约定,如果你要显示控制节点展开/收缩的图片,应该在向imaglist添加expand和collapse键值的图片,同理要显示枝干连线就要添加line和blank键值的图片。如果你提供了default图标且添加节点时没有指定的ico参数,default图标就被派上用场了。这是一种非强制的约定,你甚至可以不向imagelist添加任何图片,这样你构建的就是没有图片的树。正是因为这种约定关系使得阿赖目录树程序拥有超强的灵活性,你可以使用各种的组合,选取各种的图标,构建出各式各样的目录树来!

?

XI. 事件处理:

一、事件处理机制:

树对象的事件有:onclick , ondblclick , onmousemove , onmouseover , onmouseout , onmouseup , onmousedown , onkeypress , onkeydown , onkeyup , oncollapse , onexpand , afteradd , onblur , onfocus , onselect

节点对象的事件有:onclick , ondblclick , onmouseover , onmouseout , onmousemove , onmousedown , onmouseup , onkeypress , onkeydown , onkeyup , oncollapse , onexpand , onfocus , onblur , onselect

树对象的事件用于响应所有节点的相应事件,节点对象是针对个别的节点进行处理。有一个很重要的特点:树对象的事件处理程序的第一个参数都是引发该事件的节点对象,节点对象的事件均没有参数。我们注意到两者的事件名几乎相同(tree.afteradd事件例外),对于onclick事件它是这样执行的:当鼠标点击节点时,将会执行node.onclick的事件处理程序,如果处理程序返回值为true,接着执行tree.onclick事件,反之如果node.onclick的处理程序返回值为false(或没有返回值),则tree.onclcik事件不会被执行。其它事件都是类同于此,这就是事件处理机制,有点类似DOM(文档对象模型)的事件冒泡(bubble)。

添加节点add方法的两个参数:exeCategory和exeArgv是用来设置节点要执行的动作,例如:

n1=tree.root.add("test","","js","alert('hello')")

n2=tree.root.add("9499.net","","url","http://www.9499.net")

则单击n1将弹出"hello",单击n2将打开网址www.9499.net。如果缺省这两个参数默认动作是执行expand方法展开或收缩子节点(如果有的话)。单击节点执行的动作实际上是调用node.execute()方法,面execute()方法执行的动作又取决于exeCategory和exeArgv两个参数。node.execute()和onclick事件的联系是这样的:如果tree.onclick事件处理程序返回值为true,将接着调用node.execute()方法,若返回值为false或无返回值,则node.execute()方法不会被执行,这是事件处理机制的别一个方面。

二、事件处理程序:

事件处理程序一般用来控制节点的行为。

示例:如果我们想让节点有类似超链接的效果,即当鼠标移过时文字变蓝,加下划线,但对于节点n11却不想让它如此,可以用下面的事件处理程序实现:

//鼠标移入时
tree.οnmοuseοver=function(srcNode)
{
???? srcNode.label.style.color="blue"
???? srcNode.label.textDecoration="underline"
???? srcNode.label.cursor="hand"
}//鼠标移出时
tree.οnmοuseοut=function(srcNode)
{
??? srcNode.label.style.color="black"
??? srcNode.label.textDecoration="none"
}//对节点11特别处理
n11.οnmοuseοver=n11.οnmοuseοut=function(){return false}

另外点击节点时默认动作是让节点获得焦点选择加亮显示,如果不想让节点被选择可以让tree.onselect事件处理程序返回值为false,就可以屏蔽这个行为,如下:

tree.οnselect=function(srcNode){return false}

XII.使用模板程序:

阿赖目录树控件程序具有设计多样化树状菜单的能力,为了更方便广大使用者,我们将一些设计好的菜单封装成模板程序,这样用户就可以顺手拈来,省去样式设计的麻烦。模板程序为我们选好了使用的图片,设计了一些基本的事件处理程序,用户只须写添加节点的代码就行了,可谓快速高效,多快好省!在示例目前提供了如下几种常用的模板程序,(以后会有更多更酷的!):

alai_tree_win2k.js -- win2000 explorer风格模板
alai_tree_winxp.js -- winxp explorer风格模板
alai_tree_help.js -- chm帮助风格模板
alai_tree_pretty.js -- 一个很靓的目录树模板
alai_tree_qq.js -- QQ面板模板
alai_tree_cool.js -- COOL面板模板 (真的很酷)

现在我们以win2k模板为例,说明模板程序的使用:

一、首先加载控件程序和模板程序到网页,代码:

<SCRIPT language=JScript src="alai_tree.js"></sript>

<script src="alai_tree_win2k.js" language="JScript"></sript>

二、调用模板,添加节点:

//实例化目录树模板程序,将返回一个树对象。

var tree2=new alai_tree_win2k(divTree) //divTree是目录树放置的地方,如果缺省目录树会放到网页的最前面。

tree2.root.add("节点一")

tree2.root.add("节点二")

看,用这样的方法建目录树多省事!!其实这些模板程序并不复杂,你可以研究一下这些程序然后DIY出属于自己的模板,做出来别忘了跟我分享你的成果!

XIII. 目录树控件功能扩展:

阿赖目录树控件的功能到目前为止已经相当完美,相信你在网上找不到比这功能更强大的目录树程序了,但是它的功能还是不止于此,我们可以根据需要扩充它的功能。alai_tree_check.js是目前提供的一个扩展程序,加载目录树程序后再加载alai_tree_check,目录树控件就会增加具有添加多选按扭checkbox的节点的功能。加载alai_tree_check后目录树将增加如下成员对象:

tree.addChkNode(toNode,text,ico,exeCategory,exeArg,checked) 方法添加具有checkbox的节点(参数用途可参考tree.add方法)

tree.colChkNode 属性,保存具有checkbox的节点的集合数组

tree.oncheck 和 node.oncheck事件 点击checkbox时触发该事件

node.isCheck 属性,用于判断节点是否有checkbox

node.checkBox 属性,节点的checkbox对象

下面结合另一具模板程序pretty的使用来说明该扩展程序的使用:

一、首先加载控件程序,模板程序和扩展程序到网页(注意:扩展程序的加载一定要置后于控件程序),代码:

<script src="alai_tree.js" language="JScript"></sript>
<script src="alai_tree_pretty.js" language="JScript"></sript>
<script src="alai_tree_check.js" language="JScript"></sript>

二、调用模板,添加节点:

var tree3=new alai_tree_pretty(divTree) //divTree是目录树放置的地方,如果缺省目录树会放到网页的最前面。
tree3.root.add("节点一") //添加普通节点
tree3.addChkNode(tree3.root,"节点二") //添加有checkbox的节点