目录树控件简介
I. 概述:
目录树控件程序完全采用面向对象的方法设计,整个程序封装一个函数tree()里面,另外随目录树程序提供了一个图片列表imagelist控件。使用目录树控件程序构建目录树一般遵循以下三个步骤:
一、建立imagelist实例对象,并向控件添加建目录树所需的图片;
二、新建一个目录树控件实例,将上述imagelist实例对象作为第一个参数传递;
三、调用目录树控件的各种对象、方法,添加节点,定义事件处理程序等。
当然我们有更便捷的方法,就是使用现有的目录树模板程序以更简化的步骤来构建目录树,关于模板程序搁后再谈。在建立目录树前我先来理解目录树控件的三个核心对象:
(1)目录树控件实例对象(tree),如下:
var tree=new tree()
这样就新建了一个树对象。
(2)根(root)对象:tree.root,可以看出它是tree的一个成员,它是没有外观表现的,用于构建目录树第一级的节点,是第一级节点的父对象(parent)。
(3)节点(node)对象,对应于目录树上的一个节点,如下:
var node=tree.add(...) //添加节点,参数先省略不谈
上面调用目录添加节点的方法,生成了一个新的节点对象:node
这三个对象各自拥有很多的成员对象(属性、方法和事件)。
II. 示例程序:
var images=new aimagelist() //建立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是目录树放置的地方,
//网页上有这样的代码:<div id="divTree1"></div>,生成的目录树就插到这里面了。
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.163.com") //添加n2的子节点
var n32=tree1.add(n3,"last","www.163.com","n32","page","url","http://www.163.com") //添加n2的子节点
var colNode=tree.pathParse("/节点四/4-1;/节点四/4-2;/节点四/4-3;/节点五/")
var n4=root.addLink(www.163.com,"欢迎访问163.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、expand 和 collapse -- 用于控制子节点展开和收缩,
常用图例:
3、expand_top、expand_end、collapse_top、collapse_end,在使用上面第一组图例时提供首尾不同的图片
图例:
4、leaf 和 twig -- 用于指示树叶节点和末稍节点的图标,图例:
5、line和blank -- 用于画目录树支干连线。图例: (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 src="alai_tree.js" language="JScript"></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的节点