YUI Tree入门(二)各类Node详细分析

之前简单介绍过TreeView的使用,现在来仔细分析一下YUI TreeView的结构,Tree相关的类如下:
[img]http://meladet.iteye.com/upload/picture/pic/40590/683be4ff-05f3-3013-b243-865800184465.png[/img]
我们分成3部分看,第一部分是前面几个以Node结尾的类,这些类代表是树上的节点,其中最顶层的是Node,这个类是其他几种Node的父类。Node中有节点所具有的所有属性和方法,比如children,parent,depth,expand(),collapse()等等。
第二部分是TreeView这个类,这个类就像是一棵树的骨架,他有根有树干有树枝,可以把上面介绍的Node节点挂在Treeview上,Treeview会统一管理记录这些节点。通过TreeView你可以很方便的定位到一个或一些节点,比如 getNodeByElement(),getNodeByIndex,
getNodeByProperty(),getNodesByProperty()。通过TreeView可以控制一棵树是展开还是合拢,可以移除一些节点等等。TreeView就是在全局上控制树上的Nodes。
第三部分是最后三个类,这三个类主要是个树增加一些动画的效果。

既然TreeView是整棵树的总枢纽,我们就先从TreeView入手[b](由于TreeView的 源码太长,我就不直接贴出来,大家可以对照着源码看,碰到比较重要的代码我会把它们贴出来)[/b]。
首先是TreeView的构造函数:[b]YAHOO.widget.TreeView ( id )[/b],构造方法只有一个参数,就是HTML中的Div元素的ID,这就像是给树挖个坑中下去,以后树在页面上显示就有地方了。构造方法里面调用了TreeView的Init方法,这个方法我们稍后再说。
TreeView里面有不少属性,不过大多都不用太深究,无非是用来与HTML元素做绑定,记录TreeView的状态等等,这些属性我们只要构建好了树,就由树内部做管理,一般情况下我们都不会使用到。下面挑几个重要的属性做说明:
[b]YAHOO.widget.TreeView.nodeCount[/b],这是一个静态属性,这个属性记录TreeView上面Node的个数,也就是每次生成一个Node到TreeView上,这个属性值就增加1,这个属性有一个作用就是给Node分配一个唯一的标识,每个Node都有一个属性叫做index,这个index就是由这个属性来分配的。由于这个属性值只增不减,所以永远不会出现重复的。
[b]YAHOO.widget.TreeView.trees[/b],这是一个私有属性,它是一个关联数组,用来缓存所有的TreeView实例,每次生成一个TreeView的实例就会往trees里面设置一个key(TreeView的Id)和value(TreeView的实例)。这样方便以后通过Id可以直接取到TreeView的实例。TreeView有一个方法:YAHOO.widget.TreeView.getTree(treeId),看看它的实现:

YAHOO.widget.TreeView.getTree = function(treeId) {
var t = YAHOO.widget.TreeView.trees[treeId];//通过trees属性取值
return (t) ? t : null;
};

[b]YAHOO.widget.TreeView.counter[/b],这个也是私有属性,用来给TreeView生成一个唯一的ID,

generateId: function(el) {
var id = el.id;
if (!id) {
id = "yui-tv-auto-id-" + YAHOO.widget.TreeView.counter;
++YAHOO.widget.TreeView.counter;
}
return id;
},

这个属性的值同样是递增的,generateId方法生成的Id,在TreeView的init方法中就直接赋值给Treeview实例。
说到TreeView的init方法,我们就仔细看看它做了什么。

init: function(id) {
this.id = id;
if ("string" !== typeof id) {
this._el = id;
this.id = this.generateId(id);//通过YAHOO.widget.TreeView.counter生成
}
this.createEvent("animStart", this);
this.createEvent("animComplete", this);
this.createEvent("collapse", this);
this.createEvent("collapseComplete", this);
this.createEvent("expand", this);
this.createEvent("expandComplete", this);
this._nodes = [];
// store a global reference
YAHOO.widget.TreeView.trees[this.id] = this;
// Set up the root node
this.root = new YAHOO.widget.RootNode(this);
var LW = YAHOO.widget.LogWriter;
this.logger = (LW) ? new LW(this.toString()) : YAHOO;
this.logger.log("tree init: " + this.id);
},

Init方法做的事情很简单,给TreeView分配一个Id,创建一些事件,把TreeView实例加入到[b]YAHOO.widget.TreeView.trees[/b]数组中,生成一个RootNode。还记得我们往树上加第一个节点的时候,父节点就是用的这个RootNode,通过treeView.getRoot()这个方法可以取得。
在上次的那个例子中,最后调用了treeView.draw()来显示树,现在我们看看这个方法的实现:

draw: function() {
var html = this.root.getHtml();
this.getEl().innerHTML = html;
this.firstDraw = false;
},

this.root.getHtml()这个方法通过RootNode的getHtml得到节点的Html表示,this.getEl(),取得TreeView对应Div的对象,然后设置innerHTML。
TreeView类的介绍就到这,TreeView还有很多控制相关的方法,比如expand,collpase(),removeChildren(),getNodeByIndex()等等,这些方法实现都比较简单,而且不知道他们的实现对使用也没有什么影响,所以就不对这些方法做具体的介绍,有兴趣可以自己查看源码。
下面要说的是几个以Node结尾的类,先从顶层的[b]YAHOO.widget.Node[/b]开始。

YAHOO.widget.Node = function(oData, oParent, expanded) {
if (oData) { this.init(oData, oParent, expanded); }
};
……….
init: function(oData, oParent, expanded) {
this.data = oData;
this.children = [];
this.index = YAHOO.widget.TreeView.nodeCount;
++YAHOO.widget.TreeView.nodeCount;
this.expanded = expanded;
this.logger = new YAHOO.widget.LogWriter(this.toString());
this.createEvent("parentChange", this);
if (oParent) {
oParent.appendChild(this);
}
},
………


上面这个是构造函数和Init方法,生成一个Node需要三个参数,第一个oData,这个属性可以是任意类型的,可以是Object,这一点很重要,以后扩展树的时候可以传入你定义好的数据。第二个属性是oParent,就是你构造这个节点的父亲,值可以是树上的其他节点,第三个属性expanded,有true和false两个值,true的时候默认节点展开,false的时候不展开。
Init方法做一些初始化工作,this.index = YAHOO.widget.TreeView.nodeCount;这个是给每个Node一个唯一Id,之前介绍TreeView类的时候有说到YAHOO.widget.TreeView.nodeCount这个属性。This.children用来存储它的所有子节点,最后oParent.appendChild(this);把新生成的Node加入到oParent的children数组中。
下面把构造的过程画一张图 (图中的椭圆为属性):
[img]http://meladet.iteye.com/upload/picture/pic/40606/e3128ba6-a06b-3d47-a465-c4b1be046d2b.png[/img]
我把余下的方法进行了下简单的分类便于大家理解掌握
[b]/*插入节点的方法*/[/b]
appendTo(parentNode) {
return parentNode.appendChild(this);
}//很常用的插入节点的方法 但被插入到了参数节点子节点的最后一个
insertBefore: function(node)
如果这个节点在一个树里则先从这棵树里把该节点删除(注意:appendTo可没有删)
然后获取参数Node父节点的孩子列表以及该参数Node的位置以此操作该孩子列表在参数节点的位置前面添加
实现添加。然后重定向该节点和参数Node的前后sibling属性
最后一步 调用applyParent()方法 重设depth同时也把自己的子节点也引过来了
insertAfter: function(node)
机理同上 只在第二步操作的位置不一样罢了

[b]/*几个获取ID的方法*/[/b]
getElId() 返回这个节点容器div的id id结构:"ygtv" + this.index
getChildrenElId() 返回节点的Children节点DIV的id 注意是所有子节点在一个DIV里 id结构 "ygtvc" + this.index;
getToggleElId() 返回节点的toggle的id id结构:"ygtvt"+ this.index toggle区域就是 树种节点的左边的+ -号的区域
*这些个方法都对应有通过id获取到对象的方法 getEl() getChildrenEl() getToggleEl()

[b]/*节点的收起展开*/[/b](可以添加一些自定义的事件)
collapse() 隐藏起子节点(如果有必要的话可创建子节点)
核心是:一堆判断之后 调用 this.hideChildren()方法 此方法即获取孩子区域的对象将其display属性设为none
当然了,也调用了this.updateIcon()方法 此方法用于更新了左边的+ -显示
expand(boolean) 显示子节点 核心:也是一堆的判断 之后调用this.showChildren() 此方法即获取孩子区域的对象将其display属性设为""
expandAll() 和 collapseAll() 很显然 这两个方法是同时展开或收起所有节点以下的节点

[b]/*这个跟动态加载相关*/[/b]
setDynamicLoad(fnDataLoader, iconMode) 设置第一次展开节点时动态加载子节点数据的方法 获取方法通过参数fnDataLoader传递给节点的dataLoader属性 fnDataLoader方法的参数 第一个是Node节点类型 第二个是回调函数 如果不设置回调函数的话 在第一次加载之后节点 会关闭动态生成(即设dynamicLoadComplete为true )因为你不指定的话 会调用默认的
setDynamicLoad()第二个参数可选 int型 会赋给iconMode属性(具体用途见前面的属性解析)

[b]/*这个很重要跟自定义节点有关*/[/b]
getNodeHtml() 这个方法被设计用来被重写的 本身返回空字符串 以便支持不同种的Node. 方法会在生成节点的时候把取得的html写入节点,从而产生了各种不同的节点样式
getHtml() 这个方法= getNodeHtml()+getChildrenHtml()
getChildrenHtml() 在构建树的时候会被调用 我们总是先构建装子节点的div 但并不提供进去信息 除非这个节点被展开
refresh() 将节点getHtml()获得的html写入到子节点的区域里

getStyle() 获取节点应有的左边+ -号状态 updateIcon()方法会调用
isRoot() 返回节点是否为根节点
isChildOf(parentNode) 获取该节点在父节点的孩子节点列表中的位置 insertBefore/insertAfter方法第二步调用了该方法我自己测试的从0开始。
getSiblings() 返回所有的兄弟节点 包括节点自己
isDynamic() 返回节点的子节点是否应该是被动态生成的
getAncestor: function(depth) 返回节点某一深度的祖先

YAHOO.widget.Node就介绍到这,接下来看看继承自YAHOO.widget.Node的其他Node。[b]YAHOO.widget.RootNode[/b]的源码如下:

YAHOO.widget.RootNode = function(oTree) {
this.init(null, null, true);
this.tree = oTree;
};
YAHOO.extend(YAHOO.widget.RootNode, YAHOO.widget.Node, {

// overrides YAHOO.widget.Node
getNodeHtml: function() {
return "";
},

toString: function() {
return "RootNode";
},

loadComplete: function() {
this.tree.draw();
},

collapse: function() {},
expand: function() {}

});

很简单的实现,从构造函数来看,就是给RootNode指定一个tree属性。其Init方法都基本传入的是null,调用YAHOO.widget.Node的Init方法。getNodeHtml返回””,就是说RootNode不能显示出来,是一个隐藏的节点。其他几个方法的实现都很简单,不用多说。
[b]YAHOO.widget.HTMLNode[/b]继承自YAHOO.widget.Node,看源码可以发现HTMLNode多加了三个属性,构造函数也加了一个属性,叫hasIcon,这个属性是用来控制是否要显示树前面的那些加号、减号以及虚线等图标的。

YAHOO.widget.HTMLNode = function(oData, oParent, expanded, hasIcon) {
if (oData) {
this.init(oData, oParent, expanded);
this.initContent(oData, hasIcon);
}
};

YAHOO.extend(YAHOO.widget.HTMLNode, YAHOO.widget.Node, {
contentStyle: "ygtvhtml",
contentElId: null,
html: null,

增加的三个属性分别是:
contentStyle: "ygtvhtml",设置显示的CSS样式
contentElId: null,给Content Element设置一个ID
html: null,用来显示的Html内容
它重写的方法有toString(),getNodeHtml(),getNodeHtml()是节点显示的主要方法。
它增加的方法有initContent: function(oData, hasIcon),setHtml: function(o),这些方法的实现都很简单,不用详细说明。
[b]YAHOO.widget.TextNode[/b]是比较常用的一种Node,它根据你传入的oData来构造显示,如果传入的oData是String,则把String当作Label显示出来,如果传入的是Object,则根据Object的label属性来显示,同时还可以给Object设置style,title等属性,可以很灵活的控制节点要显示成什么样,要显示哪些信息。
具体的显示它重写了getNodeHtml()方法。新加了onLabelClick方法,在点击树节点的Label的时候触发。
最后是[b]YAHOO.widget.MenuNode[/b] ,它继承自YAHOO.widget.TextNode,只从写了toString()方法。

通过分析上面几个继承自YAHOO.widget.Node的Node,可以发现实现一个Node很简单,在init方法里面加入一些新的操作,加入一些新的属性,最后重写一些方法,就能得出符合自己要求的Node。YUI在Node的设计上做得是相当不错的,给了我们很方便的方法来扩展已有的Node。下一次我将会详细的讲解如何构建满足自己需求的Node。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值