在應(yīng)用程序中,我們經(jīng)常需要顯示或處理樹(shù)狀結(jié)構(gòu)的對(duì)象信息,比如部門(mén)信息和地區(qū)信息,樹(shù)是一種非常典型的數(shù)據(jù)結(jié)構(gòu),這些信息都可以用樹(shù)來(lái)表示。對(duì)于傳統(tǒng)的HTML頁(yè)面來(lái)說(shuō),完全依靠手動(dòng)編碼來(lái)實(shí)現(xiàn)樹(shù)是比較困難的,因?yàn)樾枰獙?xiě)很多的JS代碼,對(duì)基于AJAX異步加載來(lái)說(shuō)尤其如此,不但涉及AJAX數(shù)據(jù)異步加載,還需要考慮跨瀏覽器支持,處理起來(lái)非常麻煩,EXT中提供了現(xiàn)成的樹(shù)控件,通過(guò)這些控件,可以在B/S應(yīng)用中快速開(kāi)發(fā)出包含樹(shù)形信息結(jié)構(gòu)的應(yīng)用。

本文就是詳細(xì)介紹樹(shù)形結(jié)構(gòu)的使用過(guò)程和實(shí)例。

一、創(chuàng)建一棵樹(shù)

樹(shù)控件由Ext.tree.TreePanel類(lèi)定義,控件的名稱(chēng)為T(mén)reePanel,TreePanel類(lèi)繼承自Panel面板,在EXT中使用樹(shù)控件非常簡(jiǎn)單,我們先來(lái)看一下代碼(包含配置信息)。

  1. <html xmlns="http://www.w3.org/1999/xhtml" >  
  2. <head id="Head1" runat="server">  
  3.     <title>簡(jiǎn)單的樹(shù)形</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>  

 

這里的參數(shù)tree表示渲染的DOM的id.HTML中應(yīng)該要要有<div id="tree"></div>相對(duì)應(yīng),最后這棵樹(shù)就出現(xiàn)在這個(gè)div的位置上。

在獲得了樹(shù)形面板后,就必須要設(shè)置根,因?yàn)楸仨氂辛烁趴梢陨L(zhǎng)枝節(jié),最后生成完整的樹(shù),所以根是必須的。具體實(shí)現(xiàn)的效果如圖1所示。

1

圖1 只有根的樹(shù)

二、為樹(shù)生枝展葉

上面的實(shí)例代碼生成一棵沒(méi)有根的樹(shù),下面的代碼就為樹(shù)添加枝和葉,代碼清單如下:

  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:'區(qū)域信息'});              
  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 完整的樹(shù)控件

注意:我們一方面可以通過(guò)修改<div id="tree" style="height:300px;"></div>來(lái)設(shè)置div高度;同時(shí)也可以設(shè)置treePanel的 autoHeight屬性為tree,則可以自動(dòng)計(jì)算高度,否則展開(kāi)的樹(shù)形控件看不到枝葉。

三、使用TreeLoader獲得數(shù)據(jù)

使用上面的錄入方式來(lái)獲取數(shù)據(jù)不僅麻煩,而且還容易出錯(cuò),Ext.tree.TreeLoader可以利用從后臺(tái)獲取的數(shù)據(jù)為我們組裝出一棵樹(shù)來(lái),我們只需要提供數(shù)據(jù),讓treeLoader完成數(shù)據(jù)轉(zhuǎn)換和裝配節(jié)點(diǎn)的操作。

(1)我們要為T(mén)reePanel配置一個(gè)TreeLoader,如下面代碼所示:

  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僅包含一個(gè)參數(shù){dataUrl:'data.txt'},這個(gè)dataUrl表示在樹(shù)完成渲染后從何處讀取數(shù)據(jù)。data.txt內(nèi)容如下:

  1. [  
  2.     {text:'not leaf'},  
  3.     {text:'is leaf',leaf:true}  
  4. ]  

 

(3) 現(xiàn)在查看頁(yè)面依然只能看到根,沒(méi)有讀取數(shù)據(jù)并顯示到頁(yè)面上,因?yàn)槲覀兪褂玫腡reeNode不支持Ajax,我們需要將其改成 AsyncTreeNode,這樣才可以實(shí)現(xiàn)我們想要的異步加載效果,如下面的代碼所示:

  1. var root=new Ext.tree.AsyncTreeNode({text:'區(qū)域信息'});  
 

 

注意:必須將root.expand(true,true)修改成root.expand()避免無(wú)限循環(huán)展開(kāi)樹(shù)枝。

四、讀取本地JSON數(shù)據(jù)

讀取本地JSON其實(shí)是一種是用使用TreeLoader的另類(lèi)方法。因?yàn)橛袝r(shí)候樹(shù)形的數(shù)據(jù)并不多,為了獲取少量的數(shù)據(jù)而是用AJAX訪問(wèn)后臺(tái)實(shí)在不劃算。首先為T(mén)reePanel設(shè)置一個(gè)參數(shù)為空的TreeLoader,如下面代碼所示:

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

 

然后,設(shè)置一個(gè)根節(jié)點(diǎn),并為這個(gè)根節(jié)點(diǎn)設(shè)置children屬性,如下面代碼所示:

  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);   

 

這里需要注意幾點(diǎn):

(1) 必須設(shè)置TreeLoader,否則根節(jié)點(diǎn)會(huì)一直處于在讀取狀態(tài),無(wú)法獲得children中定義的子節(jié)點(diǎn)

(2) 根節(jié)點(diǎn)必須是AsyncTreeNode,如果是TreeNode,也無(wú)法生成子節(jié)點(diǎn)

(3) 子節(jié)點(diǎn)中的葉子節(jié)點(diǎn)必須都加上leaf:true,否則會(huì)一直顯示讀取狀態(tài)。

五、右鍵菜單

樹(shù)形彈出的右鍵菜單效果圖如圖3所示:

3

圖3 右鍵菜單效果

具體實(shí)現(xiàn)步驟如下:

(1) 制作自定義菜單,如下面的代碼所示:

  1. var contextmenu=new Ext.menu.Menu({  
  2.                 id:'theContextMenu',  
  3.                     items:[{  
  4.                         text:'點(diǎn)擊',  
  5.                         handler:function(){  
  6.                             alert(' 我被點(diǎn)中了');  
  7.                         }  
  8.                     }]  
  9.             });  

 

(2) 綁定contextmenu時(shí)間,如下面代碼所示:

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

 

六、修改節(jié)點(diǎn)的默認(rèn)圖標(biāo)

實(shí)際上,每個(gè)樹(shù)形節(jié)點(diǎn)都有icon和iconCls屬性,他們負(fù)責(zé)制定節(jié)點(diǎn)的圖標(biāo),現(xiàn)在我們來(lái)修改樹(shù)種節(jié)點(diǎn)的圖標(biāo),無(wú)論是通過(guò)new手工創(chuàng)建的節(jié)點(diǎn),還是通過(guò)JSON讀取到的節(jié)點(diǎn),設(shè)置方式都是一樣,如下面代碼所示:

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

 

七、從節(jié)點(diǎn)彈出對(duì)話(huà)框

下面的代碼可以讓對(duì)話(huà)框看起來(lái)像是從標(biāo)題上飛出來(lái)的:

  1. tree.on("click",function(node){  
  2.                 Ext.Msg.show({  
  3.                     title:'提示',  
  4.                     msg:"你單擊了"+node,  
  5.                     animEl:node.ui.textNode  
  6.                 });  
  7.             });  
  

 

八、節(jié)點(diǎn)提示信息

當(dāng)我們把鼠標(biāo)停留在某個(gè)節(jié)點(diǎn)的上方時(shí),便會(huì)出現(xiàn)提示信息,為了實(shí)現(xiàn)這種效果,我們需要對(duì)提供的JSON數(shù)據(jù)做一些修改,在JSON中添加對(duì)應(yīng)的節(jié)點(diǎn)提示信息,我們給每個(gè)節(jié)點(diǎn)數(shù)據(jù)都加上qtip:'xxx'參數(shù),這個(gè)節(jié)點(diǎn)就可以顯示提示信息了。

不過(guò),僅僅為JSON添加這個(gè)參數(shù)還不能在頁(yè)面上顯示提示信息,需要先在JS中對(duì)EXT的提示功能進(jìn)行初始化。

  1. Ext.QuickTips.init();//開(kāi)啟提示功能  

 

上面這行代碼必須在其他功能加載前完成,建議寫(xiě)在onReady函數(shù)的第一行。具體代碼如下:

  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:'點(diǎn)擊',  
  26.                         handler:function(){  
  27.                             alert('我被點(diǎn)中了');  
  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>  

 

九、為節(jié)點(diǎn)設(shè)置超鏈接

雖然我們完全可以監(jiān)聽(tīng)click事件,但是直接在節(jié)點(diǎn)樹(shù)形中設(shè)置超鏈接的地址也是一個(gè)好主意,這是很多人想實(shí)現(xiàn)的功能,具體的代碼如下:

  1. var root=new Ext.tree.AsyncTreeNode({  
  2.                 text:'我是根',  
  3.                 children:[  
  4.                     {text:'新浪網(wǎng)',qtip:'新浪網(wǎng) ',leaf:true,href:'http://www.sina.com.cn'},  
  5.                     {text:'百度中國(guó)',qtip:'搜索引擎',leaf:true,href:'http://www.baidu.cn',hrefTarget:'_blank'}  
  6.                 ]  
  7.             });