论坛首页 Web前端技术论坛

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

浏览 4115 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-07-18  
   之前简单介绍过TreeView的使用,现在来仔细分析一下YUI TreeView的结构,Tree相关的类如下:

    我们分成3部分看,第一部分是前面几个以Node结尾的类,这些类代表是树上的节点,其中最顶层的是Node,这个类是其他几种Node的父类。Node中有节点所具有的所有属性和方法,比如children,parent,depth,expand(),collapse()等等。
    第二部分是TreeView这个类,这个类就像是一棵树的骨架,他有根有树干有树枝,可以把上面介绍的Node节点挂在Treeview上,Treeview会统一管理记录这些节点。通过TreeView你可以很方便的定位到一个或一些节点,比如 getNodeByElement(),getNodeByIndex,
getNodeByProperty(),getNodesByProperty()。通过TreeView可以控制一棵树是展开还是合拢,可以移除一些节点等等。TreeView就是在全局上控制树上的Nodes。
    第三部分是最后三个类,这三个类主要是个树增加一些动画的效果。

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

YAHOO.widget.TreeView.counter,这个也是私有属性,用来给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实例加入到YAHOO.widget.TreeView.trees数组中,生成一个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结尾的类,先从顶层的YAHOO.widget.Node开始。
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数组中。
    下面把构造的过程画一张图 (图中的椭圆为属性):

我把余下的方法进行了下简单的分类便于大家理解掌握
/*插入节点的方法*/
appendTo(parentNode) {
        return parentNode.appendChild(this);
    }//很常用的插入节点的方法 但被插入到了参数节点子节点的最后一个
insertBefore: function(node)
     如果这个节点在一个树里则先从这棵树里把该节点删除(注意:appendTo可没有删)
     然后获取参数Node父节点的孩子列表以及该参数Node的位置以此操作该孩子列表在参数节点的位置前面添加
     实现添加。然后重定向该节点和参数Node的前后sibling属性
     最后一步 调用applyParent()方法 重设depth同时也把自己的子节点也引过来了
insertAfter: function(node)
     机理同上 只在第二步操作的位置不一样罢了

/*几个获取ID的方法*/
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()

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

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

/*这个很重要跟自定义节点有关*/
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。YAHOO.widget.RootNode的源码如下:
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不能显示出来,是一个隐藏的节点。其他几个方法的实现都很简单,不用多说。
    YAHOO.widget.HTMLNode继承自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),这些方法的实现都很简单,不用详细说明。
    YAHOO.widget.TextNode是比较常用的一种Node,它根据你传入的oData来构造显示,如果传入的oData是String,则把String当作Label显示出来,如果传入的是Object,则根据Object的label属性来显示,同时还可以给Object设置style,title等属性,可以很灵活的控制节点要显示成什么样,要显示哪些信息。
    具体的显示它重写了getNodeHtml()方法。新加了onLabelClick方法,在点击树节点的Label的时候触发。
    最后是YAHOO.widget.MenuNode ,它继承自YAHOO.widget.TextNode,只从写了toString()方法。
   
    通过分析上面几个继承自YAHOO.widget.Node的Node,可以发现实现一个Node很简单,在init方法里面加入一些新的操作,加入一些新的属性,最后重写一些方法,就能得出符合自己要求的Node。YUI在Node的设计上做得是相当不错的,给了我们很方便的方法来扩展已有的Node。下一次我将会详细的讲解如何构建满足自己需求的Node。




论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics