天天看點

第九章 、 TreePanel

第九章 、 TreePanel

9.1 、 TreePanel之基本使用

在 應用程式中,我們經常會涉及到要顯示或處理樹狀結構的對象資訊,比如部門資訊、地 區

資訊,或者是樹狀的菜單資訊,作業系統中的檔案夾資訊等。

對于傳統的 html 頁面來說,要自己實作顯示樹比較困難,需要寫很多的 javascript ,特

别是對于基于 Ajax 異步加載的樹來說,不但涉及到 Ajax 資料加載及處理技術,還需要考 慮

跨浏覽器支援等,處理起來非常麻煩。 ExtJS 中提供了現存的樹控件,通過這些控件可以 在

B/S 應用中快速開發出包含樹結構資訊的應用。

TreePanel TreePanel TreePanel 基本使用

樹控件由 Ext.tree.TreePanel 類定義,控件的名稱為 treepanel , TreePanel 類繼承自 Pane l

面闆。在 ExtJS 中使用樹控件其實非常簡單,我們先來看下面的代碼

Ext.onReady(function(){

var root=new Ext.tree.TreeNode({

id:"root",

text:" 樹的根 "});

root.appendChild(new Ext.tree.TreeNode({

id:"c1",

text:" 子節點 "

}));

var tree=new Ext.tree.TreePanel({

renderTo:"hello",

root:root,

width:100

});

});

代碼的第一句使用 new Ext.tree.TreeNode 類來建立一個樹節點,第二句使用樹節點的

root 的 appendChild 方法來往該節點中加入一個子節點,最後直接使用 new Ext.tree.TreePan el

來建立一個樹面闆,要樹面闆的初始化參數中指定樹的 root 屬性值為前面建立的 root 節點 ,

也就是樹根節點。上面的程式執行效果如下圖所示:

樹的節點資訊。 ExtJS 的樹控件提供了對這種功能的支援,你隻需要在建立樹控件的 時

候,通過給樹指定一個節點加載器,可以用來從伺服器端動态加載樹的節點資訊。我們來 看

下面的代碼:

var root=new Ext.tree.AsyncTreeNode({

id:"root",

text:" 樹的根 "});

var tree=new Ext.tree.TreePanel({

renderTo:"hello",

root:root,

loader: new Ext.tree.TreeLoader({url:"treedata.js"}),

width:100

});

treedata.js 這個 url 傳回的内容如下:

[{

id: 1,

text: ' 子節點 1',

leaf: true

},{

id: 2,

text: ' 兒子節點 2',

children: [{

id: 3,

text: ' 孫子節點 ',

leaf: true

}]

}]

執行上面的程式,可以得到一棵異步加載子節點的樹,點選 “ 根節點 ” 會到伺服器端 加

載子節點,如下圖所示:

當然上面的程式是一次性加載完了樹的所有節點資訊,我們也可以實作讓每一個節點 都

支援動态加載的樹,隻需要在通過伺服器請求資料的時候,每次伺服器端傳回的資料隻隻 包

含子節點,而不用把孫子節點也傳回即可。比如把上面 treedata.js 中的内容改為下面的内 容 :

[{

id: 1,

text: ' 子節點 ',

leaf: false

}]

也就是節點樹中隻包含一個子節點,而該子節點通過指定 leaf 值為 false ( 預設情況該 值

為 false) ,表示該節點不是一個葉子節點,其下面還有指節點。再執行前面的程式,不斷點

擊 “ 子節點 ” 可以得到如下圖所示的效果:

當然這是一個無限循環的樹,在實際應用中我們伺服器端傳回的資料是程式動态産生的,是以不可能每一次都産生 leaf 為 false 的節點,如果是葉子節點的時候,則需要把傳回

的 JOSN 對象中的 leaf 設定為 true 。如下所示:

[{

id: 1,

text: ' 子節點 ',

leaf:true

}]

事件處理

當然,僅僅能顯示一棵樹還不夠,我們一般還需要在使用者點選樹節點的時候執行相應 的

東西,比如打開某一個連接配接,執行某一個函數等,這就需要使用到事件處理。比如下面的 代

碼:

Ext.onReady(function(){

var root=new Ext.tree.TreeNode({

id:"root",

text:" 樹的根 "});

var c1=new Ext.tree.TreeNode({

id:"c1",

text:" 子節點 "

});

root.appendChild(c1);

var tree=new Ext.tree.TreePanel({

renderTo:"hello",

root:root,

width:100

});

tree.on("click",function(node,event){

alert(" 您點選了 "+node.text);

}

);

c1.on("click",function(node,event){

alert(" 您點選了 "+node.text);

}

);

});

執行上面的程式,當使用者點選樹控件中的任意節點時,都會彈出一個提示資訊框,當

使用者點選 c1 這個子節點時,會彈出兩次提示資訊框。因為我們除了指定 tree 的 click 事件 響

應函數以外,另外又給 node 節點指定單獨的事件響應函數。

當然,如果隻是要實作當點選樹節點時跳到某一個指定 url 的功能則非常簡單。看下 面的代碼:

Ext.onReady(function(){

var root=new Ext.tree.TreeNode({

id:"root",

href:"http://www.easyjf.com/",

hrefTarget:"_blank",

text:" 樹的根 "});

var c1=new Ext.tree.TreeNode({

id:"c1",

href:"http://wlr.easyjf.com/",

hrefTarget:"_blank",

text:" 子節點 "

});

root.appendChild(c1);

var tree=new Ext.tree.TreePanel({

renderTo:"hello",

root:root,

width:100

});

});

執行程式,點選樹節點,将會在浏覽新視窗中打開節點中 href 指定的連結。

9.2 、 TreeNode

在 ExtJS 中,不管是葉子節點還是非葉子節點,都統一用 TreeNode 表表示樹的節點。

在 ExtJS 中,有兩種類型的樹節點。一種節點是普通的簡單樹節點,由 Ext.tree.TreeNode 定

義,另外一種是需要異步加載子節點資訊的樹節點,該類由 Ext.tree.AsyncTreeNode 定義。 看

下面的代碼:

Ext.onReady(function(){

var tree=new Ext.tree.TreePanel({

renderTo:"hello",

root:new Ext.tree.AsyncTreeNode({

text:" 根節點 "

}),

width:100

});

});

執行程式,點選樹中的 “ 根節點 ” 則會一直發現樹會嘗試加載這個節點的子節點,由 這裡沒有指定樹的加載器,是以 “ 根節點 ” 會變成一直處于加載的狀态。如下圖所示:

對于普通的 TreeNode 來說,可以通過調用節點的 appendChild 、 removeChild 等方法來

往該節點中加入子節點或删除子節點等操作。

TreeNode 與 AsyncTreeNode 可以同時使用,比如下面的代碼:

Ext.onReady(function(){

var root=new Ext.tree.TreeNode({

id:"root",

text:" 樹的根 "

});

var c1=new Ext.tree.TreeNode({

text:" 子節點 1"

})

var c2=new Ext.tree.AsyncTreeNode({

text:" 子節點 2"

});

root.appendChild(c1);

root.appendChild(c2);

var tree=new Ext.tree.TreePanel({

renderTo:"hello",

root:root,

width:300,

loader:new Ext.tree.TreeLoader({

applyLoader:false,

url:"http://www.cnblogs.com/liu2008hz/admin/%22treedata.js"

})

});

});

treedata.js 中的内容仍然是:

[{

id: 1,

text: ' 子節點 '

}]

執行上面的程式可以得到一棵如下圖所示的樹:

ExtJS 實用簡明教程

另外要在樹以外的程式中得到目前選擇的節點,可以通過 TreePanel 的

getSelectionModel 方法來獲得,該方法預設傳回的是 Ext.tree.DefaultSelectionModel 對象,

DefaultSelectionModel 的 getSelectedNode 方法傳回目前選擇的樹節點。比如要得到樹 tree 中

中目前選擇節點,代碼如下:

tree.getSelectionModel().getSelectedNode()

9.3 、 TreeLoader

對于 ExtJS 中的樹來說,樹加載器 TreeLoader 是一個比較關鍵的部件,樹加載器由

Ext.tree.TreeLoader 類定義,隻有 AsyncTreeNode 才會使用 TreeLoader 。看下面的代碼:

Ext.onReady(function(){

var loader=new Ext.tree.TreeLoader({

url:"http://www.cnblogs.com/liu2008hz/admin/%22treedata.js"

});

var root=new Ext.tree.AsyncTreeNode({

id:"root",

text:" 根節點 ",

loader:loader});

var tree=new Ext.tree.TreePanel({

renderTo:"hello",

root:root,

width:100

});

});

首先我們使用 Ext.tree.TreeLoader 來初始化了一個 TreeLoader 對象,構造函數中的配 置

數 url 表示獲得樹節點資訊的 url 。然後在初始化根節點的時候我們使用的是

ncTreeNode ,在該節點中指定該節點的 laoder 為前面定義的 loader 。執行這段程式,在

擊 “ 根節點 ” 時,會從伺服器端指定 root 節點的子節點資訊。

TreeLoader 嚴格來說是針對樹的節點來定義的,可以給樹中的每一個節點定義不同的

eLoader ,預設情況下,如果一個 AsyncTreeNode 節點在準備加載子節點的時候,如果 該

點上沒有定義 loader ,則會使用 TreePanel 中定義的 loader 作為加載器。是以,我們可以

接在 TreePanel 上面指定 loader 屬性,這樣就不需要給每一個節點指定具體的 TreeLoader

。是以,上面的代碼可以改成如下所示的内容 :

9.3  、 TreeLoader

對于 ExtJS 中的樹來說,樹加載器 TreeLoader 是一個比較關鍵的部件,樹加載器由

Ext.tree.TreeLoader 類定義,隻有 AsyncTreeNode 才會使用 TreeLoader 。看下面的代碼:

Ext.onReady(function(){

var loader=new Ext.tree.TreeLoader({

url:"http://www.cnblogs.com/liu2008hz/admin/%22treedata.js"

});

var root=new Ext.tree.AsyncTreeNode({

id:"root",

text:" 根節點 ",

loader:loader});

var tree=new Ext.tree.TreePanel({

renderTo:"hello",

root:root,

width:100

});

});

首先我們使用 Ext.tree.TreeLoader 來初始化了一個 TreeLoader 對象,構造函數中的配 置

參數 url 表示獲得樹節點資訊的 url 。然後在初始化根節點的時候我們使用的是

AsyncTreeNode ,在該節點中指定該節點的 laoder 為前面定義的 loader 。執行這段程式,在

點選 “ 根節點 ” 時,會從伺服器端指定 root 節點的子節點資訊。

TreeLoader 嚴格來說是針對樹的節點來定義的,可以給樹中的每一個節點定義不同的

TreeLoader ,預設情況下,如果一個 AsyncTreeNode 節點在準備加載子節點的時候,如果 該

節點上沒有定義 loader ,則會使用 TreePanel 中定義的 loader 作為加載器。是以,我們可以

直接在 TreePanel 上面指定 loader 屬性,這樣就不需要給每一個節點指定具體的 TreeLoader

了。是以,上面的代碼可以改成如下所示的内容 :

9.4  自定義 TreeLoader

在 ExtJS 自己的 TreeLoader 中,當要實作從遠端伺服器端異步加載樹節點資訊的時候,

都是通過請求伺服器上的某一個 URL 來進行的,這個 URL 傳回下面的資訊:

[{

id: 1,

text: 'A leaf Node',

leaf: true

},{

id: 2,

text: 'A folder Node',

children: [{

id: 3,

text: 'A child Node',

leaf: true

}]

}]

假如我們是直接通過類似 DWR 或 EasyJWeb 的遠端腳本引擎在用戶端直接調用伺服器

的業務方法,直接跳過了 WEB (不需要 Struts 、 JSP 或其它 Web 層的代碼)這一層,這時

我們沒有 URL ,這時該怎麼辦呢?這就需要使用到自定義的 TreeLoader ,下面我們通過一

個執行個體來做簡單的講解。

看伺服器端的 ITopicCategoryService

public interface ITopicCategoryService {

List loadCategory(Long id);

}

loadCategory 方法傳回一個類型為 Node 的清單,也就是傳回指定 id 的下級分類信節點

資訊, Node 對應樹節點的資訊,代碼如下:

public class Node {

private TopicCategory category;

Node(TopicCategory category) {

this.category = category;

}

public String getId() {

return category.getId().toString();

}

public boolean getLeaf() {

return category.getChildren().size() < 1;

}

public String getText() {

return category.getName();

}

public String getQtip() {

return category.getName();

}

}

Node 在這裡相當于一個簡單擴充卡,其實就是把資料庫中的日志分類實體适配成包樹

節點對象。

把 ITopicCategoryService 釋出成可供用戶端遠端調用,使用 EasyJWeb 的話引如下面三

個 js :

<script type="text/javascript" src="/ejf/easyajax/prototype.js"></script>

<script type="text/javascript" src="/ejf/easyajax/engine.js"></script>

<script type="text/javascript" src="/ejf/easyajax/topicCategoryService.js"></script>

使用 DWR 的話引入下面的兩個 js :

<script type="text/javascript" src="/dwr/dwr/engine.js "></script>

<script type="text/javascript" src="/dwr/dwr/util.js "></script>

<script type="text/javascript" src="/dwr/dwr/interface/ topicCategoryService.js "></script>

這樣我們可以在頁使用下面的 javascrpt 來從伺服器端獲得某一個節點的子節點資訊,

代碼如下:

function test()

{

topicCategoryService.loadCategory(1,function(ret)

{

alert(" 一共有 "+ret.length+" 個子節點 ");

}

}

如何讓 ExtJS 的樹面闆能通過這個遠端 web 腳本方法 topicCategoryService.loadCategory

來加載異步加載樹節點資訊呢?其實很簡單,跟一般的使用沒什麼兩樣,樹面闆 TreePanel

的代碼如下:

var tree = new Ext.tree.TreePanel({

autoScroll:true,

animate:true,

width:'100px',

height:'300px',

enableDD:true,

containerScroll: true,

loader: loader

root: new Ext.tree.AsyncTreeNode({

text: ' 日志分類 ',

id:'root'

});

});

然後差別是在 loader 部分,使用遠端 Web 調用來加載樹節點的 loader ,代碼如下:

var loader=new WebInvokeTreeLoader({

fn:topicCategoryService.loadCategory

});

loader.on("beforeload",function(l,node){

l.args[0]=(node.id!='root'?node.id:"-1");

});

再回顧一下傳統的直接通過 url 加載樹節點的 TreeLoader 代碼,如下所示:

var loader=new Ext.tree.TreeLoader({

url:"http://www.cnblogs.com/liu2008hz/admin/'/topicCategory.ejf?cmd=getCategory&pageSize=-1&treeData=true'

});

loader.on("beforeloader",function(loader,node){

loader.baseParams.id=(node.id!='root'?node.id:"");

});

差別在于,遠端腳本調用方式加載樹節點資訊使用的是 WebInvokeTreeLoader ,需要通

過 fn 屬性來指定用于加載資料的遠端方法,并在 beforeload 事件處理器設定參數遠端方法

調用的參數值。而傳統的樹節點加載器是 Ext.tree.TreeLoader ,需要指定一個 url 來獲得 jso n

資料。

WebInvokeTreeLoader 是自定義的樹加載器,代碼其實比較簡單,你可以自己寫一個。 本

方案僅供參考,關于 WebInvokeTreeLoader 的源代碼我已經傳到了我用 ExtJS 開發的 Blog

示例網站上了,僅供 VIP 會員浏覽,有興趣的朋友可跟我聯系。

轉載于:https://www.cnblogs.com/liu2008hz/archive/2010/10/27/1862702.html