原先系统使用xtree读取数据库构造的树,是jsp一次性生成所有的节点的,因为数据量也不大,所以用用还挺好。今天特来兴致,决定改造。当点击父节点的时候,才去数据库动态的获取子节点,这样对于大数据量的系统,性能比较好。
首先下载 http://webfx.eae.net/dhtml/xtree2b/xtree2b-20050606.zip
这包里面有简单的示例,废话少说,动手
- <link type="text/css" rel="stylesheet" href="<%=request.getContextPath() %>/css/xtree2.css">
- <link type="text/css" rel="stylesheet" href="<%=request.getContextPath() %>/css/xtree2.links.css">
- <script type="text/javascript" src="<%=request.getContextPath() %>/script/xtree2.js"></script>
- <script type="text/javascript" src="<%=request.getContextPath() %>/script/xloadtree2.js"></script>
首先构造树的jsp文件要加载相关js和css文件,上面down的zip里面都有,放到你的项目里面
jsp端加入脚本,构造树
- <div style="left:20px;top:30px;width:100%;">
- <script>
- var tree = new WebFXTree('root node');
- tree.add(new WebFXLoadTreeItem("all node", "/cmsCatalogQueryAction.do?method=tree","javascript:modifyNode('cmsCatalogMaintAction.do?method=new')"));
- tree.showRootNode = false;
- tree.showRootLines = false;
- tree.write();
- </script>
/cmsCatalogQueryAction.do?method=tree是生成相关xml的action地址
javascript:modifyNode('cmsCatalogMaintAction.do?method=new')这个是点击根节点的时候action的地址,比如链接到添加一级节点的页面,(modifyNode是我项目里面用的js函数,目的是在右边的frame里面打开后面的参数地址)
tree.showRootNode = false;
tree.showRootLines = false;
为了把all node作为根节点,所以隐藏root node节点
下面看看action端的写法
- public ActionForward tree(
- ActionMapping actionMapping,
- ActionForm actionForm,
- HttpServletRequest request,
- HttpServletResponse response)
- throws Exception {
- response.setContentType("text/xml; charset=gbk");
- response.setHeader("Cache-Control", "no-cache");
- response.setDateHeader("Expires", 0);
- PrintWriter out = response.getWriter();
- String id = request.getParameter("id");
- Document doc = new Document(new Element("tree"));
- if (StringUtils.isEmpty(id)) {
- List list = getCmsFacade().getRootCatalogListByDomainID(HConstant.currentDomain.getId());
- transfer(doc, list);
- } else {
- List list = getCmsFacade().getCmsCatalogListByParentID(id);
- transfer(doc, list);
- }
- Format format = Format.getCompactFormat();
- format.setEncoding("gbk");
- format.setIndent("/t");
- XMLOutputter xout = new XMLOutputter(format);
- xout.output(doc, out);
- out.flush();
- out.close();
- return null;
- } // end tree
- private void transfer(Document doc, List r) {
- for (Iterator it = r.iterator(); it.hasNext();) {
- CmsCatalog one = (CmsCatalog) it.next();
- Element tree = doc.getRootElement();
- Element inner = new Element("tree").setAttribute("text", one.getZhCaption());
- tree.addContent(inner);
- inner.setAttribute("src", "/cmsCatalogQueryAction.do?method=tree&id="+ one.getId());
- inner.setAttribute("action", "javascript:refun('"+one.getId()+"','"+one.getZhCaption()+"')");
- }
- }
这边的代码要根据你的业务来写了,我的栏目对象叫CmsCatalog。生成xml使用了jdom,代码中的Document 和Element这些class都是这个包里面的
getCmsFacade().getRootCatalogListByDomainID是获取本站点的所有一级栏目,
getCmsFacade().getCmsCatalogListByParentID是根据父ID得到下一级栏目列表,(不是得到所有的子,只获取直接下级的子)
获取到栏目list后,要转换成对应xml规范,参看transfer方法,转后的数据格式如下,以根节点为例
- <?xml version="1.0" encoding="gbk" ?>
- - <tree>
- <tree text="关于我们" src="/cmsCatalogQueryAction.do?method=tree&id=4028e44919c7e5290119c7e754330001" action="javascript:refun('4028e44919c7e5290119c7e754330001','关于我们')" />
- <tree text="新闻频道" src="/cmsCatalogQueryAction.do?method=tree&id=4028e4491a04a4fb011a04ab42ae005e" action="javascript:refun('4028e4491a04a4fb011a04ab42ae005e','新闻频道')" />
- <tree text="产品与解决方案" src="/cmsCatalogQueryAction.do?method=tree&id=4028e4491a80ec5b011a811c1b570002" action="javascript:refun('4028e4491a80ec5b011a811c1b570002','产品与解决方案')" />
- <tree text="服务与支持" src="/cmsCatalogQueryAction.do?method=tree&id=4028e4491a900271011a9042bb810003" action="javascript:refun('4028e4491a900271011a9042bb810003','服务与支持')" />
- <tree text="英才导航" src="/cmsCatalogQueryAction.do?method=tree&id=4028e4491a33c105011a33d2f5b90002" action="javascript:refun('4028e4491a33c105011a33d2f5b90002','英才导航')" />
- <tree text="联系我们" src="/cmsCatalogQueryAction.do?method=tree&id=4028e4491a805657011a80d2cae90006" action="javascript:refun('4028e4491a805657011a80d2cae90006','联系我们')" />
- </tree>
当点击一个节点的时候,会执行refun这个js函数,为什么不直接写一个链接呢? 因为一个栏目树可能在很多地方都要用到,点击树的链接也因此可能不一样了,所以不能在action写死具体地址。构造树的jsp页面直接写一个refun函数就ok了,自己去定义点击节点时候的操作。服务端返回了两个栏目参数给refun函数,一个是id,一个中文名称
当点击最后一级节点的时候,会提示加载节点错误的信息,这个是xloadtree的一个bug,我们手动修改下就ok了,编辑xloadtree2.js文件,找到
if (count == 0) {
jsNode.errorText = "Error loading " + jsNode.src + " (???)";
}
修改为
if (count == 0) {
jsNode.remove(jsNode._loadingItem);
t.setSuspendRedraw(false);
jsNode.update();
return;
}
当返回的xml 为空的时候,把节点设置为无子节点
到此,动态加载树就完成了,相当简单吧,你唯一要做的就是合理的把你的栏目列表从数据库取出来,然后正确的填充到xml里面,就ok了