多叉树结合JavaScript树形控件实现无限级树形菜单一种构建多级有序树形结构JSON或XML数据源的方法.docx
- 文档编号:3850692
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:22
- 大小:326.23KB
多叉树结合JavaScript树形控件实现无限级树形菜单一种构建多级有序树形结构JSON或XML数据源的方法.docx
《多叉树结合JavaScript树形控件实现无限级树形菜单一种构建多级有序树形结构JSON或XML数据源的方法.docx》由会员分享,可在线阅读,更多相关《多叉树结合JavaScript树形控件实现无限级树形菜单一种构建多级有序树形结构JSON或XML数据源的方法.docx(22页珍藏版)》请在冰点文库上搜索。
多叉树结合JavaScript树形控件实现无限级树形菜单一种构建多级有序树形结构JSON或XML数据源的方法
多叉树结合JavaScript树形控件实现无限级树形菜单(一种构建多级有序树形结构JSON(或XML)数据源的方法)
一、问题研究的背景和意义
在Web应用程序开发领域,基于AJAX技术的JavaScript树形控件已经被广泛使用,它用来在Html页面上展现具有层次结构的数据项。
目前市场上常见的JavaScript框架及组件库中均包含自己的树形控件,例如JQuery、Dojo、YahooUI、ExtJS等,还有一些独立的树形控件,例如dhtmlxtree等,这些树形控件完美的解决了层次数据的展示问题。
展示离不开数据,树形控件主要利用AJAX技术从服务器端获取数据源,数据源的格式主要包括JSON、XML等,而这些层次数据一般都存储在数据库中。
“无限级树形菜单”,顾名思义,没有级别的限制,它的数据通常来自数据库中的无限级层次数据,这种数据的存储表通常包括id和parentId这两个字段,以此来表示数据之间的层次关系。
现在问题来了,既然树形控件的数据源采用JSON或XML等格式的字符串来组织层次数据,而层次数据又存储在数据库的表中,那么如何建立起树形控件与层次数据之间的关系,换句话说,如何将数据库中的层次数据转换成对应的层次结构的JSON或XML格式的字符串,返回给客户端的JavaScript树形控件?
这就是我们要解决的关键技术问题。
本文将以目前市场上比较火热的ExtJS框架为例,讲述实现无限级树形菜单的方法,该方法同样适用于其它类似的JS树形控件。
ExtJS框架是富客户端开发中出类拔萃的框架之一。
在Ext的UI控件中,树形控件无疑是最为常用的控件之一,它用来实现树形结构的菜单。
TreeNode用来实现静态的树形菜单,AsyncTreeNode用来实现动态的异步加载树形菜单,后者最为常用,它通过接收服务器端返回来的JSON格式的数据,动态生成树形菜单节点。
动态生成树有两种思路:
一种是一次性生成全部树节点,另一种是逐级加载树节点(利用AJAX,每次点击节点时查询下一级节点)。
对于大数据量的菜单节点来说,逐级加载是比较合适的选择,但是对于小数据量的菜单来说,一次性生成全部节点应该是最为合理的方案。
在实际应用开发中,一般不会遇到特别大数据量的场景,所以一次性生成全部菜单节点是我们重点研究的技术点,也就是本文要解决的关键技术问题。
本文以基于ExtJS的应用系统为例,讲述如何将数据库中的无限级层次数据一次性在界面中生成全部菜单节点(例如在界面中以树形方式一次性展示出银行所有分支机构的信息),同时对每一个层次的菜单节点按照某一属性和规则排序,展示出有序的菜单树。
解决一次性构造无限级树形菜单的问题,可以拓展出更多的应用场景,例如树形结构表格TreeGrid,一次性生成树形表格,对树形表格进行完整分页,对表格列进行全排序;或者可以利用本文的思路扩展出其他的更复杂的应用场景。
先看两个图例,有个直观上的认识:
图一,银行分支机构树形结构菜单
图二,树形结构表格
二、详细设计方案
让我们先看两段代码片段:
文件一,branchTree.html(Ext树形控件页面)
Ext.onReady(
function(){
vartree=newExt.tree.TreePanel({
height:
300,
width:
400,
animate:
true,
enableDD:
true,
containerScroll:
true,
rootVisible:
false,
frame:
true,
//getBranch.do请求服务器返回多级树形结构的JSON字符串
loader:
newExt.tree.TreeLoader({dataUrl:
'getBranch.do'}),
root:
newExt.tree.AsyncTreeNode({id:
'0',text:
'根结点'})
});
tree.expandAll();
}
);
文件二,branchTreeJSON.jsp(接收getBranch.do请求,返回多级树形结构的JSON字符串)
<%
//读取银行分支机构的层次数据
Listresult=DataAccess.getBankInfoList();
//将层次数据转换为多叉树对象(本文下面会详细介绍该数据结构的实现方法)
Noderoot=ExtTreeHelper.createExtTree(result);
%>
[
<%=root.toString()%>
--以JSON的形式返回响应数据,Ext.tree.TreeLoader会根据此数据生成树形菜单-->
]
以上两个程序文件是一次性生成无限级树形菜单所必须的,其中最为关键的部分就是如何生成一个无限级的树形结构JSON字符串,返回给客户端的Ext树形控件。
对于银行分支机构来说,需要返回类似如下的JSON串:
{
id:
'100000',
text:
'廊坊银行总行',
children:
[
{
id:
'110000',
text:
'廊坊分行',
children:
[
{
id:
'113000',
text:
'廊坊银行开发区支行',
leaf:
true
},
{
id:
'112000',
text:
'廊坊银行解放道支行',
children:
[
{
id:
'112200',
text:
'廊坊银行三大街支行',
leaf:
true
},
{
id:
'112100',
text:
'廊坊银行广阳道支行',
leaf:
true
}
]
},
{
id:
'111000',
text:
'廊坊银行金光道支行',
leaf:
true
}
]
}
]
}
同时还需要对树中每一个层次的节点按照某一属性(比如分支机构编号)进行排序,以展示出有序的树形菜单。
现在可以把问题概括为:
1、把数据库中的层次数据转换成多级树形结构的JSON格式的字符串
2、对树中每一个层次的节点按照某一属性(比如分支机构编号)进行排序
下面介绍解决问题的思路:
在数据结构这门课中,我们都学过树,无限级树形菜单就可以抽象成一种多叉树结构,即每个节点下包含多个子节点的树形结构,首先就需要把数据库中的层次数据转换成多叉树结构的对象树,也就是构造出一棵多叉树。
有了数据结构,还要实现相应的算法,我们需要实现两种算法:
1、兄弟节点横向排序算法,对隶属于同一个父节点下面的所有直接子节点按照某一节点属性和规则进行排序,保持兄弟节点横向有序;
2、先序遍历算法,递归打印出无限级JSON字符串。
概括起来分为三步:
1、构造无序的多叉树结构
2、实现兄弟节点横向排序方法
3、实现先序遍历方法,打印出JSON字符串
如图所示:
我们给这棵树起个名字吧,就叫做multipletree ,简称M-Tree。
三、源代码实现(Java语言版)
实现这样一颗树,需要设计三个类:
树类(MultipleTree.java)、节点类(Node.java)、孩子列表类(Children.java);为了方便演示,还需要构造一些假的层次数据,因此还需要建一个构造假数据的类(VirtualDataGenerator.java),以下代码拷贝出来之后可直接运行测试:
packagetest;
importjava.util.ArrayList;
importjava.util.Comparator;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.List;
importjava.util.Map;
importjava.util.Set;
importjava.util.Collections;
/**
*多叉树类
*/
publicclassMultipleTree{
publicstaticvoidmain(String[]args){
//读取层次数据结果集列表
ListdataList=VirtualDataGenerator.getVirtualResult();
//节点列表(散列表,用于临时存储节点对象)
HashMapnodeList=newHashMap();
//根节点
Noderoot=null;
//根据结果集构造节点列表(存入散列表)
for(Iteratorit=dataList.iterator();it.hasNext();){
MapdataRecord=(Map)it.next();
Nodenode=newNode();
node.id=(String)dataRecord.get("id");
node.text=(String)dataRecord.get("text");
node.parentId=(String)dataRecord.get("parentId");
nodeList.put(node.id,node);
}
//构造无序的多叉树
SetentrySet=nodeList.entrySet();
for(Iteratorit=entrySet.iterator();it.hasNext();){
Nodenode=(Node)((Map.Entry)it.next()).getValue();
if(node.parentId==null||node.parentId.equals("")){
root=node;
}else{
((Node)nodeList.get(node.parentId)).addChild(node);
}
}
//输出无序的树形菜单的JSON字符串
System.out.println(root.toString());
//对多叉树进行横向排序
root.sortChildren();
//输出有序的树形菜单的JSON字符串
System.out.println(root.toString());
//程序输出结果如下(无序的树形菜单)(格式化后的结果):
//{
//id:
'100000',
//text:
'廊坊银行总行',
//children:
[
//{
//id:
'110000',
//text:
'廊坊分行',
//children:
[
//{
//id:
'113000',
//text:
'廊坊银行开发区支行',
//leaf:
true
//},
//{
//id:
'111000',
//text:
'廊坊银行金光道支行',
//leaf:
true
//},
//{
//id:
'112000',
//text:
'廊坊银行解放道支行',
//children:
[
//{
//id:
'112200',
//text:
'廊坊银行三大街支行',
//leaf:
true
//},
//{
//id:
'112100',
//text:
'廊坊银行广阳道支行',
//leaf:
true
//}
//]
//}
//]
//}
//]
//}
//程序输出结果如下(有序的树形菜单)(格式化后的结果):
//{
//id:
'100000',
//text:
'廊坊银行总行',
//children:
[
//{
//id:
'110000',
//text:
'廊坊分行',
//children:
[
//{
//id:
'111000',
//text:
'廊坊银行金光道支行',
//leaf:
true
//},
//{
//id:
'112000',
//text:
'廊坊银行解放道支行',
//children:
[
//{
//id:
'112100',
//text:
'廊坊银行广阳道支行',
//leaf:
true
//},
//{
//id:
'112200',
//text:
'廊坊银行三大街支行',
//leaf:
true
//}
//]
//},
//{
//id:
'113000',
//text:
'廊坊银行开发区支行',
//leaf:
true
//}
//]
//}
//]
//}
}
}
/**
*节点类
*/
classNode{
/**
*节点编号
*/
publicStringid;
/**
*节点内容
*/
publicStringtext;
/**
*父节点编号
*/
publicStringparentId;
/**
*孩子节点列表
*/
privateChildrenchildren=newChildren();
//先序遍历,拼接JSON字符串
publicStringtoString(){
Stringresult="{"
+"id:
'"+id+"'"
+",text:
'"+text+"'";
if(children!
=null&&children.getSize()!
=0){
result+=",children:
"+children.toString();
}else{
result+=",leaf:
true";
}
returnresult+"}";
}
//兄弟节点横向排序
publicvoidsortChildren(){
if(children!
=null&&children.getSize()!
=0){
children.sortChildren();
}
}
//添加孩子节点
publicvoidaddChild(Nodenode){
this.children.addChild(node);
}
}
/**
*孩子列表类
*/
classChildren{
privateListlist=newArrayList();
publicintgetSize(){
returnlist.size();
}
publicvoidaddChild(Nodenode){
list.add(node);
}
//拼接孩子节点的JSON字符串
publicStringtoString(){
Stringresult="[";
for(Iteratorit=list.iterator();it.hasNext();){
result+=((Node)it.next()).toString();
result+=",";
}
result=result.substring(0,result.length()-1);
result+="]";
returnresult;
}
//孩子节点排序
publicvoidsortChildren(){
//对本层节点进行排序
//可根据不同的排序属性,传入不同的比较器,这里传入ID比较器
Collections.sort(list,newNodeIDComparator());
//对每个节点的下一层节点进行排序
for(Iteratorit=list.iterator();it.hasNext();){
((Node)it.next()).sortChildren();
}
}
}
/**
*节点比较器
*/
classNodeIDComparatorimplementsComparator{
//按照节点编号比较
publicintcompare(Objecto1,Objecto2){
intj1=Integer.parseInt(((Node)o1).id);
intj2=Integer.parseInt(((Node)o2).id);
return(j1 -1: (j1==j2? 0: 1)); } } /** *构造虚拟的层次数据 */ classVirtualDataGenerator{ //构造无序的结果集列表,实际应用中,该数据应该从数据库中查询获得; publicstaticListgetVirtualResult(){ ListdataList=newArrayList(); HashMapdataRecord1=newHashMap(); dataRecord1.put("id","112000"); dataRecord1.put("text","廊坊银行解放道支行"); dataRecord1.put("parentId","110000"); HashMapdataRecord2=newHashMap(); dataRecord2.put("id","112200"); dataRecord2.put("text","廊坊银行三大街支行"); dataRecord2.put("parentId","112000"); HashMapdataRecord3=newHashMap(); dataRecord3.put("id","112100"); dataRecord3.put("text","廊坊银行广阳道支行"); dataRecord3.put("parentId","112000"); HashMapdataRecord4=newHashMap(); dataRecord4.put("id","113000"); dataRecord4.put("text","廊坊银行开发区支行"); dataRecord4.put("parentId","110000"); HashMapdataRecord5=newHashMap(); dataRecord5.put("id","100000"); dataRecord5.put("text","廊坊银行总行"); dataRecord5.put("parentId",""); HashMapdataRecord6=newHashMap(); dataRecord6.put("id","110000"); dataRecord6.put("text","廊坊分行"); dataRecord6.put("parentId","100000"); HashMapdataRecord7=newHashMap(); dataRecord7.put("id","111000"); dataRecord7.put("text","廊坊银行金光道支行"); dataRecord7.put("parentId","110000"); dataList.add(dataRecord1); dataList.add(dataRecord2); dataList.add(dataRecord3); dataList.add(dataRecord4); dataList.add(dataRecord5); dataList.add(dataRecord6); dataList.add(dataRecord7); returndataList; } } 好了,通过上面的代码,就可以实现多叉树的兄弟节点横向排序和先序遍历了,实现了将层次数据转换为有序无限级树形结构JSON字符串的目的。 在实际的项目中,可以把上面的有效代码融入其中,或者在此基础上进行一些扩展: 1、实现对指定层次的排序(例如只排序第
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多叉树 结合 JavaScript 树形 控件 实现 无限 菜单 一种 构建 多级 有序 结构 JSON XML 数据源 方法
链接地址:https://www.bingdoc.com/p-3850692.html