正文

Ext树的构造2008-10-18 12:40:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lovebugs/38965.html

分享到:

3.1. 真的,我是为了树,才开始学ext的。

 

之前使用过xtree和dojo中的tree,感觉都是怪怪的,界面简陋,功能也不好上手,待看到ext里的树形真是眼前一亮,在此之前,动态增添,修改删除节点,拖拽和右键菜单,我一直认为是不可能实现的任务,而在ext上却轻松实现了,而且界面和动画效果相当完美。真是让人爱不释手啊。

树形是非常典型的一种数据结构,多级菜单,部门组织结构,省市县三级这种金字塔结构都可以用树形表示,要表示一个老爸有一帮孩子的情况真是非树形莫属啊,做好了这部分,绝对是个亮点。

3.2. 传统是先做出一棵树来。

 

树形世界的万物之初是一个TreePanel。

var tree = new Ext.tree.TreePanel('tree');

这里的参数'tree',表示渲染的dom的id。html写着个<div id="tree"></div>做呼应呢,最后这棵树就出现在这个div的位置上。

现在我们获得了树形面板,既然是树就必须有一个根,有了根才能在上边加枝子,放叶子,最后装饰的像一棵树似的。嗯,所以根是必要的,我们就研究研究这个根是怎么咕哝出来的。

var root = new Ext.tree.TreeNode({text:'偶是根'});

看到了吧,它自己都说它自己是根了,所以它就肯定是根没错。再看下面。

tree.setRootNode(root);
tree.render();

首先,我们把这个根root,放到tree里,用了setRootNode()方法,就是告诉tree,这是一个根,你可得把它放好啊。

立刻对tree进行渲染,让它出现在id="tree"的地方,这个id可是在上面指定的,如果有疑问,请翻回去继续研究,我们就不等你,继续了。

当当,我非常荣幸的向您宣布,咱们的第一棵树出来了。这是它的照片。

 

靠,这是树吗?

嗯,现在的确不太像树,因为它只有一个根。

靠,我们要的是树,你就搞出一个根来,有鸟用啊。

嗯,理论上等它自己发芽长成树,可能性是比较小,不如咱们偷偷插上几个枝子,说不定看起来就更像树了。

注意

虽然只有一个根,不过也算是棵树,1.x的例子在lingo-sample/1.1.1/03-01.html。

3.3. 超越一个根

 

上回书说道,我们要偷偷插上几个杈子,让这个本来就是树的树,更像一棵树。

var root = new Ext.tree.TreeNode({text:'偶是根'});
var node1 = new Ext.tree.TreeNode({text:'偶是根的第一个枝子'});
var node2 = new Ext.tree.TreeNode({text:'偶是根的第一个枝子的第一个叶子'});
var node3 = new Ext.tree.TreeNode({text:'偶是根的第一个叶子'});
node1.appendChild(node2);
root.appendChild(node1);
root.appendChild(node3);

我们从外边拿来三个TreeNode,不管不顾就把node2插到node1上,node1,node2一起插到root上,这下好了,咱们的树立刻就像是一棵树了。

 

咦?它怎么还是这么点儿东西?客官莫急,待小二儿给你整治一番,即看庐山真面目。

 

嗯,现在的确有点儿意思了,不过它开始的时候就那么缩在一团,看着很不爽,每次都要点这么几下才能看到底下的东西,咱们有没有办法让它每次渲染好就自己展开呢?

方法当然有咯,请上眼。

root.expand(true, true);

这一下就能解您燃眉之急,第一个参数是说,是否递归展开所有子节点,如果是false,就只展开第一级子节点,子节点下面还是折叠着的,。第二个参数是说是否有动画效果,true的话,你可以明显看出来那些节点是一点儿点儿展开的,否则就是刷拉一下子就出来了.

为了方便,咱们的例子里直接就可以展开了,省的再去点啊。1.x的例子在lingo-sample/1.1.1/03-02.html。

3.4. 你不会认为2.0里跟1.x是一样的吧?

 

第一个区别就是TreePanel的定义,原来的id要放到{}中,对应的名字是el。像这样改:

var tree = new Ext.tree.TreePanel({
    el:'tree'
});

即使这样改完了,还是什么都看不见,我们错过了什么?用findbug看了一下dom,height竟然是0,当然啥也看不见了,2.0里的树为啥不会自动伸缩呢,只好咱们给它设置一个初始高度,在html里设置个300px的高度,就可以显示出来了。

<div id="tree" style="height:300px;"></div>

另一个也如法炮制。我们就可以看到2.0比1.x多了鼠标移到树节点上时的高亮显示。

 

好了,看了这些例子,应该对树型有些认识了,虽然这里只有TreeNode,却能表示枝杈或者叶子,原理很简单,如果这个TreeNode下有其他节点,它就是一个枝杈,如果没有,它就是一个叶子,从它前头的图标就很容易看出来。嘿嘿,根其实就是一个没有上级节点的枝杈了。实际上,他们都是TreeNode而已,属性不同而已。

2.0的例子在lingo-sample/2.0/目录下,分别是03-01.html和03-02.html。

3.5. 这种装配树节点的形式,真是让人头大。

 

如此刀耕火种不但麻烦,而且容易犯错,有没有更简便一些的方法吗?答案是利用Ext.tree.TreeLoader和后台进行数据交换,我们在只提供数据,让TreeLoader帮咱们做数据转换和装配节点的操作。

啦啦啦,json和ajax要登场了,不过你是否还记得我说过,一旦涉及到ajax就需要配合服务器了,ajax是无法从本地文件系统直接取得数据的。

首先,让我们为TreePanel加上TreeLoader

var tree = new Ext.tree.TreePanel('tree', {
    loader: new Ext.tree.TreeLoader({dataUrl: '03-03.txt'})
});

在此,TreeLoader仅包含一个参数dataUrl: '03-03.txt',这个dataUrl表示,在渲染后要去哪里读取数据,为了方便模拟,我们写了一个txt文本文件提供数据,直接打开03-03.txt可以看到里边的内容。

[
    {text:'not leaf'},
    {text:'is leaf',leaf:true}
]

里边是一个包含了两个节点定义的数组,可能你会发觉那个多出来的属性leaf:true,它的效果很神奇,这一点我们马上就可以看到。

如果你现在就去匆匆忙忙的刷新页面,想看一下咱们的成果,那一定会失望而归,页面上没有像你期待的那样,从03-03.txt读取数据,显示到页面上,你依然只能看到那个孤零零的根。这是因为TreeNode是不支持ajax的,我们需要把根节点换成AsyncTreeNode,它可以实现咱们的愿望。

var root = new Ext.tree.AsyncTreeNode({text:'偶是根'});
 

估计谁第一次看到这场面都一定吓傻了。我们不是只定义了两个节点吗?怎么一下子跑出这么多东西来?先别着急,让我们先把root.expand(true, true)改成root.expand(),避免节点无限展开下去,然后慢慢研究这个情况。

 

现在场面被控制住了,取消了递归展开,只展开根节点的第一层节点,我们得到的确实是与03-03.txt文件里相对应的两个节点,不过这两个节点有些不同,not leaf节点的图标赫然是枝杈的图标,如果点击它前面的加号,便又成了上面的场景。Why?

原因就来自AsyncTreeNode,这个东西会继承根节点TreeLoader中dataUrl,你点展开的时候,会执行这个节点的expand()方法,ajax会跑到dataUrl指定的地址去取数据,用firebug可以看到当前节点id会作为参数传递给dataUrl指定的地址,这样我们的后台就可以通过这个节点的id计算出该返回什么数据,得到了数据TreeLoader去解析数据并装配成子节点,然后显示出来。

哈哈,现在就是关键部分了。因为咱们使用的03-03.txt提供的数据,不会判断当前节点的id,所以每次返回的数据都是一样的,这就是树会无限循环下去的原因了。

那么为啥只有第一个节点会无限循环下去呢?第二个节点就没有那个小加号,呵呵~因为第二个节点不是AsyncTreeNode ,TreeLoader在生成节点的时候会判断数据里的leaf属性,如果是leaf:true,那么就会生成TreeNode而不是AsyncTreeNode,TreeNode可不会自动去用ajax取值,自然就不会无限循环展开了。

现实中,异步读取属性的节点是很爽的一件事情,因为你可能要保存成千上万条节点记录。一次性全部装载的话,无论读取和渲染的速度都会很慢。使用异步读取的方式,只有点击某一节点的时候,才去获得子节点属性,并进行渲染,极大的提高了用户体验。而且ext的树形本身有缓存机制,打开一次,再点击也不会去重复读取了,提升了响应速度。

html例子,1.x版本在lingo-sample/1.1.1/03-03.html,2.0版本在lingo-sample/2.0/03-03.html。

为了巩固学习效果,咱们再写一个json获得数据的例子,这次的json稍微写复杂一点儿。

 

这次对应的json数据文件是03-04.txt。

[
    {text:'01',children:[
        {text:'01-01',leaf:true},
        {text:'01-02',children:[
            {text:'01-02-01',leaf:true},
            {text:'01-02-02',leaf:true}
        ]},
        {text:'01-03',leaf:true}
    ]},
    {text:'02',leaf:true}
]

这也可以看作是在数据不多的情况下,一次加载所有数据的途径,只要确保所有叶子节点上都加上leaf:true的属性,就不会出现循环展开的问题了。

阅读(6894) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册