在应用程序中,我们经常需要显示或处理树状结构的对象信息,比如部门信息和地区信息,树是一种非常典型的数据结构,这些信息都可以用树来表示。对于传统的HTML页面来说,完全依靠手动编码来实现树是比较困难的,因为需要写很多的JS代码,对基于AJAX异步加载来说尤其如此,不但涉及AJAX数据异步加载,还需要考虑跨浏览器支持,处理起来非常麻烦,EXT中提供了现成的树控件,通过这些控件,可以在B/S应用中快速开发出包含树形信息结构的应用。

本文就是详细介绍树形结构的使用过程和实例。

一、创建一棵树

树控件由Ext.tree.TreePanel类定义,控件的名称为TreePanel,TreePanel类继承自Panel面板,在EXT中使用树控件非常简单,我们先来看一下代码(包含配置信息)。

?

view plaincopy to clipboardprint?
  1. <html?xmlns="http://www.w3.org/1999/xhtml"?>??
  2. <head?id="Head1"?runat="server">??
  3. ????<title>简单的树形</title>??
  4. ????<link?rel="stylesheet"?type="text/css"?href="../resources/css/ext-all.css"/>??
  5. ????<script?type="text/javascript"?src="../adapter/ext/ext-base.js"</script>??
  6. ????<script?type="text/javascript"?src="../ext-all.js"></script>??
  7. ????<script?type="text/javascript"><!--??
  8. ????????Ext.onReady(function(){??
  9. ????????????var?tree=new?Ext.tree.TreePanel({??
  10. ????????????????el:'tree'??
  11. ????????????});??
  12. ????????????var?root=new?Ext.tree.TreeNode({text:'我是根'});??
  13. ????????????tree.setRootNode(root);??
  14. ????????????tree.render();??????????????
  15. ????????});??????
  16. </script>??
  17. </head>??
  18. <body>??
  19. ?<div?id="tree"></div>??
  20. </body>??
  21. </html>??

?

这里的参数tree表示渲染的DOM的id.HTML中应该要要有<div id="tree"></div>相对应,最后这棵树就出现在这个div的位置上。

在获得了树形面板后,就必须要设置根,因为必须有了根才可以生长枝节,最后生成完整的树,所以根是必须的。具体实现的效果如图1所示。

1

图1 只有根的树

二、为树生枝展叶

上面的实例代码生成一棵没有根的树,下面的代码就为树添加枝和叶,代码清单如下:

?

view plaincopy to clipboardprint?
  1. <script?type="text/javascript">??
  2. ????????Ext.onReady(function(){??
  3. ????????????var?tree=new?Ext.tree.TreePanel({??
  4. ????????????????el:'tree',??
  5. ????????????????autoHeight:true??
  6. ????????????});??
  7. ????????????var?root=new?Ext.tree.TreeNode({text:'区域信息'});??????????????
  8. ????????????var?node1=new?Ext.tree.TreeNode({text:'湖南省'});??
  9. ????????????var?node3=new?Ext.tree.TreeNode({text:'广东省'});??
  10. ????????????var?node2=new?Ext.tree.TreeNode({text:'广州市'});????
  11. ??????????????????????
  12. ????????????node3.appendChild(node2);??
  13. ????????????root.appendChild(node1);??
  14. ????????????root.appendChild(node3);???
  15. ????????????tree.setRootNode(root);????
  16. ????????????????????????
  17. ????????????tree.render();??????????????
  18. ????????});??
  19. ?</script>??

?

效果图如图2所示:

2

图2 完整的树控件

注意:我们一方面可以通过修改<div id="tree" style="height:300px;"></div>来设置div高度;同时也可以设置treePanel的 autoHeight属性为tree,则可以自动计算高度,否则展开的树形控件看不到枝叶。

三、使用TreeLoader获得数据

使用上面的录入方式来获取数据不仅麻烦,而且还容易出错,Ext.tree.TreeLoader可以利用从后台获取的数据为我们组装出一棵树来,我们只需要提供数据,让treeLoader完成数据转换和装配节点的操作。

(1)我们要为TreePanel配置一个TreeLoader,如下面代码所示:

?

view plaincopy to clipboardprint?
  1. var?tree=new?Ext.tree.TreePanel({??
  2. ????????????????el:'tree',??
  3. ????????????????loader:new?Ext.tree.TreeLoader({dataUrl:'data.txt'}),??????????????????
  4. ????????????????autoHeight:true??
  5. ????????????});??

?

(2)这里的TreeLoader仅包含一个参数{dataUrl:'data.txt'},这个dataUrl表示在树完成渲染后从何处读取数据。data.txt内容如下:

?

view plaincopy to clipboardprint?
  1. [??
  2. ????{text:'not?leaf'},??
  3. ????{text:'is?leaf',leaf:true}??
  4. ]??

?

(3) 现在查看页面依然只能看到根,没有读取数据并显示到页面上,因为我们使用的TreeNode不支持Ajax,我们需要将其改成 AsyncTreeNode,这样才可以实现我们想要的异步加载效果,如下面的代码所示:

?

view plaincopy to clipboardprint?
  1. var?root=new?Ext.tree.AsyncTreeNode({text:'区域信息'});??
?

?

注意:必须将root.expand(true,true)修改成root.expand()避免无限循环展开树枝。

四、读取本地JSON数据

读取本地JSON其实是一种是用使用TreeLoader的另类方法。因为有时候树形的数据并不多,为了获取少量的数据而是用AJAX访问后台实在不划算。首先为TreePanel设置一个参数为空的TreeLoader,如下面代码所示:

?

view plaincopy to clipboardprint?
  1. var?tree=new?Ext.tree.TreePanel({??
  2. ????????????????el:'tree',??
  3. ????????????????loader:new?Ext.tree.TreeLoader(),??????????????????
  4. ????????????????autoHeight:true??
  5. ????????????});??

?

然后,设置一个根节点,并为这个根节点设置children属性,如下面代码所示:

?

view plaincopy to clipboardprint?
  1. var?root=new?Ext.tree.AsyncTreeNode({??
  2. ????????????????text:'我是根',??
  3. ????????????????children:[??
  4. ????????????????????{text:'Leaf?No.1',leaf:true},??
  5. ????????????????????{text:'Leaf?No.1',leaf:true}??
  6. ????????????????]??
  7. ????????????});??
  8. ????????????tree.setRootNode(root);???

?

这里需要注意几点:

(1) 必须设置TreeLoader,否则根节点会一直处于在读取状态,无法获得children中定义的子节点

(2) 根节点必须是AsyncTreeNode,如果是TreeNode,也无法生成子节点

(3) 子节点中的叶子节点必须都加上leaf:true,否则会一直显示读取状态。

五、右键菜单

树形弹出的右键菜单效果图如图3所示:

3

图3 右键菜单效果

具体实现步骤如下:

(1) 制作自定义菜单,如下面的代码所示:

?

view plaincopy to clipboardprint?
  1. var?contextmenu=new?Ext.menu.Menu({??
  2. ????????????????id:'theContextMenu',??
  3. ????????????????????items:[{??
  4. ????????????????????????text:'点击',??
  5. ????????????????????????handler:function(){??
  6. ????????????????????????????alert(' 我被点中了');??
  7. ????????????????????????}??
  8. ????????????????????}]??
  9. ????????????});??

?

(2) 绑定contextmenu时间,如下面代码所示:

?

view plaincopy to clipboardprint?
  1. tree.on("contextmenu",function(node,e){??
  2. ????????????????e.preventDefault();??
  3. ????????????????node.select();??
  4. ????????????????contextmenu.showAt(e.getXY());??
  5. ????????????});??

?

六、修改节点的默认图标

实际上,每个树形节点都有icon和iconCls属性,他们负责制定节点的图标,现在我们来修改树种节点的图标,无论是通过new手工创建的节点,还是通过JSON读取到的节点,设置方式都是一样,如下面代码所示:

?

view plaincopy to clipboardprint?
  1. var?root1=new?Ext.tree.TreeNode({??
  2. ????????????????text:'icon',??
  3. ????????????????icon:'user_female.png'??
  4. ????????????});??

?

七、从节点弹出对话框

下面的代码可以让对话框看起来像是从标题上飞出来的:

?

view plaincopy to clipboardprint?
  1. tree.on("click",function(node){??
  2. ????????????????Ext.Msg.show({??
  3. ????????????????????title:'提示',??
  4. ????????????????????msg:"你单击了"+node,??
  5. ????????????????????animEl:node.ui.textNode??
  6. ????????????????});??
  7. ????????????});??
??

?

八、节点提示信息

当我们把鼠标停留在某个节点的上方时,便会出现提示信息,为了实现这种效果,我们需要对提供的JSON数据做一些修改,在JSON中添加对应的节点提示信息,我们给每个节点数据都加上qtip:'xxx'参数,这个节点就可以显示提示信息了。

不过,仅仅为JSON添加这个参数还不能在页面上显示提示信息,需要先在JS中对EXT的提示功能进行初始化。

?

view plaincopy to clipboardprint?
  1. Ext.QuickTips.init();//开启提示功能??

?

上面这行代码必须在其他功能加载前完成,建议写在onReady函数的第一行。具体代码如下:

?

view plaincopy to clipboardprint?
  1. <script?type="text/javascript">??
  2. ????????Ext.onReady(function(){??
  3. ????????????Ext.QuickTips.init();??
  4. ????????????var?tree=new?Ext.tree.TreePanel({??
  5. ????????????????el:'tree',??
  6. ????????????????loader:new?Ext.tree.TreeLoader(),??????????????????
  7. ????????????????autoHeight:true??
  8. ????????????});??
  9. ????????????var?root=new?Ext.tree.AsyncTreeNode({??
  10. ????????????????text:'我是根',??
  11. ????????????????children:[??
  12. ????????????????????{text:'Leaf?No.1',qtip:'No1',leaf:true},??
  13. ????????????????????{text:'Leaf?No.1',qtip:'No2',leaf:true}??
  14. ????????????????]??
  15. ????????????});??
  16. ????????????var?root1=new?Ext.tree.TreeNode({??
  17. ????????????????text:'icon',??
  18. ????????????????icon:'user_female.png'??
  19. ????????????});??
  20. ????????????tree.setRootNode(root);???
  21. ????????????//root.expand(true,true);??
  22. ????????????var?contextmenu=new?Ext.menu.Menu({??
  23. ????????????????id:'theContextMenu',??
  24. ????????????????????items:[{??
  25. ????????????????????????text:'点击',??
  26. ????????????????????????handler:function(){??
  27. ????????????????????????????alert('我被点中了');??
  28. ????????????????????????}??
  29. ????????????????????}]??
  30. ????????????});??
  31. ????????????tree.on("contextmenu",function(node,e){??
  32. ????????????????e.preventDefault();??
  33. ????????????????node.select();??
  34. ????????????????contextmenu.showAt(e.getXY());??
  35. ????????????});??
  36. ????????????tree.on("click",function(node){??
  37. ????????????????Ext.Msg.show({??
  38. ????????????????????title:'提示',??
  39. ????????????????????msg:"你单击了"+node,??
  40. ????????????????????animEl:node.ui.textNode??
  41. ????????????????});??
  42. ????????????});??
  43. ????????????tree.render();????????????????????????
  44. ?????????????????????????
  45. ????????});??
  46. </script>??

?

九、为节点设置超链接

虽然我们完全可以监听click事件,但是直接在节点树形中设置超链接的地址也是一个好主意,这是很多人想实现的功能,具体的代码如下:

?

view plaincopy to clipboardprint?
  1. var?root=new?Ext.tree.AsyncTreeNode({??
  2. ????????????????text:'我是根',??
  3. ????????????????children:[??
  4. ????????????????????{text:'新浪网',qtip:'新浪网 ',leaf:true,href:'http://www.sina.com.cn'},??
  5. ????????????????????{text:'百度中国',qtip:'搜索引擎',leaf:true,href:'http://www.baidu.cn',hrefTarget:'_blank'}??
  6. ????????????????]??
  7. ????????????});??

?

?