<t:tree2> 以 HTML 表格渲染樹狀結構,支持動態展開/折疊。其核心特性在於雙模式交互:
clientSideToggle="true",預設):整棵樹一次性渲染至瀏覽器,JavaScript 處理展開/折疊,無網絡往返,體驗流暢。clientSideToggle="false"):每次點擊觸發 Request/Response 週期,僅傳輸可見節點,適合大數據量或低帶寬場景。假設:深度 4 層、平均分支 4、每節點 200 字符 HTML。
客戶端模式總傳輸量 ≈ 1 + 4 + 16 + 64 = 85 個節點 × 200 字符 = 17 KB(僅示例)。
實際生產環境中,節點包含圖標、鏈接、樣式、隱藏字段,單節點常超過 1 KB。百萬級節點樹將產生數百 MB HTML,導致:
決策原則:節點總數 < 500 且內網環境 → 客戶端模式;否則強制服務端模式。
組件綁定 #{myHandler.treeModel},TreeModel 封裝根 TreeNode。TreeNode 接口四大核心方法:
| 方法 | 職責 | 實現要點 |
|---|---|---|
getType() | 返回節點類型標識,決定使用哪個 <f:facet> 渲染 | 不可返回 null;無匹配 facet 拋異常 |
isLeaf() | 判斷是否葉子節點(不可展開) | 必須與 getChildren().isEmpty() 一致 |
getChildCount() | 返回子節點數量,支持延遲加載 | 僅計數,不實例化子節點,關鍵優化點 |
getChildren() | 返回子節點 List,順序即渲染順序 | 不含 null;size() 必須等於 getChildCount() |
public class LazyTreeNode implements TreeNode {
private String id;
private List<TreeNode> children; // null 表示未加載
public int getChildCount() {
return childCountFromDB(id); // 僅查 count(*)
}
public List<TreeNode> getChildren() {
if (children == null) {
children = loadChildrenFromDB(id); // 真正加載
}
return children;
}
// isLeaf()、getType()...
}
配合 clientSideToggle="false",用戶點擊「+」時才觸發查詢,極大降低首屏負載。
<t:tree2 value="#{handler.treeModel}" var="node" clientSideToggle="false">
<f:facet name="folder">
<h:commandLink action="#{node.toggleExpanded}">
<h:graphicImage value="/icons/folder.png" />
<h:outputText value="#{node.name}" />
</h:commandLink>
</f:facet>
<f:facet name="document">
<h:outputText value="#{node.name}" styleClass="leaf-node" />
</f:facet>
</t:tree2>
getType() 返回 "folder" 或 "document",JSF 自動選擇對應 Facet。可為不同業務類型定義專屬渲染邏輯(如權限圖標、拖拽控制柄)。
<t:tree2 ... showNav="false">
<f:facet name="folder">
<h:commandLink action="#{tree.toggleExpanded}"
actionListener="#{navigationBacker.processAction}">
<h:graphicImage value="/icons/folder_open.png" />
<h:outputText value="#{node.name}" />
</h:commandLink>
</f:facet>
</t:tree2>
showNav="false" 移除默認「+/-」圖標,commandLink 綁定 tree.toggleExpanded 實現點擊資料夾展開,actionListener 可記錄展開狀態或執行權限檢查。
getChildren() 返回可分頁的 List 包裝類。JSF Tree2 通過模式切換與延遲加載契約,優雅解決了樹狀組件的性能與體驗難題。關鍵在於:誠實評估數據規模,果斷選擇服務端模式,並徹底落實 getChildCount()/getChildren() 分離加載。配合 Facet 機制,可構建出企業級的權限樹、組織架構樹、文件瀏覽器等複雜場景。