使用JS生成树形结构的菜单是基于J2EE的B/S系统常用的UI方式。但长期以来的问题是同步(即一次加载整棵树)加载一棵完整的树给前台及后台同时带来压力,由于加载数据及渲染时间过长使用户体验度很低。Ajax的异步数据传输方式是解决此问题的较好方式,即每次只加载一层节点,当需要时才加载下级节点,这样页面无需一次加载解决了此问题。
Ext的TreePanel组件提供了此功能即异步树(asynchronism tree),使用其实现需以下两步:
实现预览:
1. 首先是JavaBean的节点模型(Tree Node Model):
/** * Method: 异步加载树型结点<br> * Origin Time: 2008-8-15 下午03:56:28<br> * * @author Seraph<br> * @email: [email protected]<br> */ public class AsyncTreeNode { private String id; private String text; // 结点显示名称 private boolean leaf; // 是否为叶子结点 private boolean disabled; // 是否可用 private String cls; // 显示的样式,file、folder private String iconCls; // 结点图标样式 private String href; // 点击后时的链接 private String hrefTarget; // 在何frame中显示 private boolean draggable; // 是否可拖拽 // Omit the get and set method ... ... }
数据库中的表结构:
COLUMN_NAME |
DATA_TYPE |
ID | NUMBER |
PARENT |
NUMBER |
TEXT | VARCHAR2 |
LEAF | VARCHAR2 |
DISABLED | VARCHAR2 |
CLS |
VARCHAR2 |
ICON_CLS |
VARCHAR2 |
HREF |
VARCHAR2 |
HREF_TARGET |
VARCHAR2 |
取下级节点的接口定义:
/** * Method: 获取异步加载树型子结点<br> * Author: Seraph<br> * Origin Time: 2008-9-9 下午05:46:02<br> * * @param menuId 当前结点的id * @return 下级节点组成的List */ public List getLowerTreeNodes(String menuId);
数据提供的Spring的Controller:
/** * Method:<br> * Origin Time: 2008-8-15 上午11:07:55<br> * @author Seraph<br> * @email: [email protected]<br> */ public class AsyncTreeProviderController extends JsonProviderController { private TreeManager treeManager; public void setTreeManager(TreeManager treeManager) { this.treeManager = treeManager; } protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { String rootId = request.getParameter("id"); List list = treeManager.getLowerTreeNodes(rootId); super.pushJsonResponse(response, list); return null; } }
此步将查询到的下级结点的List<AsyncTreeNode>转换为JSON数据通过Ajax方式返回给Ext的TreePanel组件用以渲染下级结点。
PS: 推荐使用json-lib来转换javabean为json数据。下面是json-lib的maven的dependency。
<dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.2.2</version> </dependency>
2. JavaScript的Ext TreePanel组件实现:
/** * async-tree.js Power by YUI-EXT and JSON. * * @author Seraph * @email [email protected] */ var AsyncTree = { author: "Seraph", version: "0.1.0" }; // -> Configuration of tree. e.g: CG[1] var CG = { 1: "asyncTreeProvider.do", 2: "async" }; // -> Root-node name in Chinese. e.g: CN[1] var CN = { 1: "菜单", 2: "配置" }; // -> Root-node ID of tree. e.g: ID[1] var ID = { 1: "-1", 2: "-2" }; Ext.onReady(function(){ var Tree = Ext.tree; var myTreeLoader = new Ext.tree.TreeLoader({ url: CG[1] }); myTreeLoader.on("beforeload", function(treeLoader, node) { myTreeLoader.baseParams.id = node.attributes.id; }, myTreeLoader); var tree = new Tree.TreePanel({ el:'tree1', autoScroll:true, autoHeight: true, border: false, animate:true, enableDD:true, rootVisible:false, containerScroll: true, loader: myTreeLoader, root: { nodeType: CG[2], text: CN[1], id: ID[1] } }); tree.render(); tree.getRootNode().expand(); });