程式扎記: [ ExtJS3.x 開發實戰 ] CH5 : 樹形結構 - Part1

標籤

2013年2月18日 星期一

[ ExtJS3.x 開發實戰 ] CH5 : 樹形結構 - Part1

Preface: 
樹的控制項由 Ext.tree.TreePanel 類別定義, 控制項的名稱為 Treepanel. TreePanel 類別繼承自 Panel 面板. 在 Ext 中使用樹控制項非常簡單, 先參考簡單代碼如下: 
  1. var tree = new Ext.tree.TreePanel({  
  2.     el: 'tree'  
  3. });  
這裡的參數 tree 表示 render 之 DOM 的 id. 在 HTML 有 div tag 相對應. 現在我們建立了樹形面板. 既然是樹就必須有根, 有了根才能在上面生長枝節最後成為一棵樹. 我們透過下面程式碼看看根是如何生成的 : 
  1. var root = new Ext.tree.TreeNode({text: 'Root'});  
  2. tree.setRootNode(root);  
  3. tree.render();  
這樣我們就建立的一棵只有根的樹. 

TreePanel 簡單範例: 
上面已經建立一棵只有根的樹, 接下來我們要為樹加上枝與葉, 讓它看上去更像一棵樹. 參考代碼如下: 
  1. var root = new Ext.tree.TreeNode({  
  2.     text:'Root'  
  3. });  
  4.   
  5. var node1 = new Ext.tree.TreeNode({  
  6.     text: 'Node1'  
  7. });  
  8. var node2 = new Ext.tree.TreeNode({  
  9.     text: 'Leaf1'  
  10. });  
  11. var node3 = new Ext.tree.TreeNode({  
  12.     text: 'Leaf2'  
  13. });  
  14.   
  15. node1.appendChild(node2);  
  16. root.appendChild(node1);  
  17. root.appendChild(node3);  
執行結果如下: 
 

預設樹是沒有展開的, 我們可以使用下面代碼讓樹預設是展開的: 
  1. root.expand(truetrue);  
第一個參數說明是否展開自 root 以下的子節點 (如果為 false 則指展開第一級的子節點; true 則展開所有子節點); 第二個參數說明是否呈現動畫展開過程. 

tree 的配置 與 使用 TreeLoader 取得資料: 
我們也可以如下配置 TreePanel
  1. var tree = new Ext.tree.TreePanel({  
  2.     renderTo:'tree',  
  3.     root: new Ext.tree.TreeNode({text: 'Root'})  
  4. });  
上面透過屬性 root 設定根結點; renderTo 屬性設定載入的 DOM 節點. 

像上面那樣獲取資料不但麻煩而且容易出錯. 透過 Ext.tree.TreeLoader 可以利用從後台獲取資料組裝出一棵樹來, 而我們只要提供資料, 讓 TreeLoader 完成資料轉換和裝配節點的操作. 而這樣的動作自然又少不了 JSON 與 Ajax, 一旦涉及 Ajax 就需要配置伺服器. 首先我們需要為 TreePanel 設置一個 TreeLoader, 參考代碼如下: 
  1. var tree = new Ext.tree.TreePanel({  
  2.     el:'tree',  
  3.     loader: new Ext.tree.TreeLoader({dataUrl: '1.txt'})  
  4. });  
  5.       
  6. var root = new Ext.tree.AsyncTreeNode({text:'Root'});    
  7.     
  8.    tree.setRootNode(root);    
  9.    tree.render();    
  10.   
  11.    root.expand();   
- 1.txt 
  1. [  
  2.     {text: 'not leaf'},  
  3.     {text: 'is leaf', leaf: true}  
  4. ]  
而上面代碼得到的頁面結果如下: 
 

當你不斷點節 "+" 的節點時會發現數會無止盡的 expand 下去, 原因就在於 AsyncTreeNode 會繼承樹形 TreeLoader 中的 dataUrl. 當你展開節點時或執行對應節點的 expand() 方法時, 它會透過 Ajax 連結 dataUrl 指定的位址並會取資料, 而且還會把自己的 id 最為參數傳遞給 dataUrl 指定的位址. 而我們後台應該透過節點 id 計算出該返回的資料, TreeLoader 會根據獲得相應資料為樹形裝配節點, 並顯示到頁面上. 關鍵就在於我們使用 1.txt 提供的資料不會判斷當前的節點 id. 所以每次返回的資料都是一樣的, 也就是為什麼樹會無窮的展開下去的原因. 

接著有著上面的了解, 我們提供一個較正常的 JSON 檔 2.txt 如下: 
- 2.txt 
  1. [    
  2.     {text:'01',children:[    
  3.         {text:'01-01',leaf:true},    
  4.         {text:'01-02',children:[    
  5.             {text:'01-02-01',leaf:true},    
  6.             {text:'01-02-02',leaf:true}    
  7.         ]},    
  8.         {text:'01-03',leaf:true}    
  9.     ]},    
  10.     {text:'02',leaf:true}    
  11. ]  
執行頁面結果如下: 
 

讀取本機 JSON 資料: 
讀取本機 json 是 TreeLoader 的特殊使用方法. 因為有時候樹形資料並不多, 為了獲取少量資料而使用 Ajax 連結後台並不划算. 可是如果退到每個節點都使用 new 來生成又嫌麻煩. 那麼便可以使用下面方法讓 TreeLoader 讀取本機 JavaScript 中的 JSON 資料然後生成樹形節點. 首先為 TreePanel 設定一個參數為空的 TreeLoader, 然後設定根節點並為它設定 children 屬性放置 JSON: 
  1. Ext.onReady(function(){       
  2.     var tree = new Ext.tree.TreePanel({  
  3.         el:'tree',  
  4.         loader: new Ext.tree.TreeLoader()  
  5.     });  
  6.           
  7.     var root = new Ext.tree.AsyncTreeNode({  
  8.         text:'Root',  
  9.         children:[  
  10.                   {text: 'Leaf No.1', leaf: true},  
  11.                   {text: 'Leaf No.2', leaf: true}  
  12.                   ]  
  13.     });    
  14.         
  15.     tree.setRootNode(root);    
  16.     tree.render();    
  17.     
  18.     root.expand();   
  19. });  
頁面執行結果如下 
 

使用 JSP 提供後提資料: 
之前範例使用 HTML 與 JavaScript 顯示樹形節點; 現在我們要把 TreeLoader 中的 dataUrl 改成我們現在用到的 tree.jsp, 修改後的代碼如下: 
  1. var tree = new Ext.tree.TreePanel({  
  2.     el:'tree',  
  3.     loader: new Ext.tree.TreeLoader({dataUrl: 'tree.jsp'})  
  4. });  
  5.       
  6. var root = new Ext.tree.AsyncTreeNode({  
  7.     text:'Root',  
  8.     id: '0'  
  9. });    
  10.     
  11.    tree.setRootNode(root);    
  12.    tree.render();    
  13.   
  14.    root.expand();  
這邊我們給 root 節點設定一個 id, 這樣後台才能知道何時返回節點對應的子節點資料. 前台準備就緒, 接著來看後台 tree.jsp 的程式碼: 
  1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
  2. <%  
  3.     request.setCharacterEncoding("UTF-8");  
  4.     response.setCharacterEncoding("UTF-8");  
  5.       
  6.     // obtain node id  
  7.     String node = request.getParameter("node");  
  8.     System.out.printf("Expand Node-%s...\n", node);  
  9.       
  10.     String json = "";  
  11.     if("0".equals(node))  
  12.     {  
  13.         json+="[{id:1, text:'Node1'},{id:2, text:'Node2'}]";  
  14.     }  
  15.     else if("1".equals(node))  
  16.     {  
  17.         json+="[{id:11, text:'Node11'},{id:12, text:'Leaf12', leaf:true}]";  
  18.     }  
  19.     else if("2".equals(node))  
  20.     {  
  21.         json+="[{id:21, text:'Leaf21', leaf:true}]";  
  22.     }  
  23.     else if("11".equals(node))  
  24.     {  
  25.         json+="[{id:111, text:'Leaf111', leaf:true}]";  
  26.     }  
  27.       
  28.     response.getWriter().print(json);  
  29. %>  
執行頁面結果如下: 
 

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!