第九章 、 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