二话不说,先看看效果图:
1、先来看写死的:
展开前~~
展开后~~
怎么实现呢?
先new 一个jsp文件,导入几个包,编写html代码,编写js代码,一个文件搞定!
1 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6 <title>Insert title here</title>
7 <script type="text/javascript" src="../bootstrap-3.3.7-dist/treeview/jquery.js"></script>
8 <script type="text/javascript" src="../js/jquery.treetable.js"></script>
9 <link rel="stylesheet" type="text/css" href="../css/jquery.treetable.css">
10 <link rel="stylesheet" type="text/css" href="../css/jquery.treetable.theme.default.css">
11 <script type="text/javascript">
12 $(document).ready(function(){
13 $("#treeTable").treetable({
14 expandable : true,
15 initialState:"expanded",
16 //expandable : true
17 clickableNodeNames:true,//点击节点名称也打开子节点.
18 indent : 30//每个分支缩进的像素数。
19 });
20 });
21 </script>
22 </head>
23 <body>
24 <div>
25 <table id="treeTable" style="width:800px">
26 <tr>
27 <td>名字</td>
28 <td>URL</td>
29 <td>操作<td>
30 </tr>
31 <tr data-tt-id="a">
32 <td>a</td>
33 <td>a.jsp</td>
34 <td><button>edit</button> <td>
35 </tr>
36 <tr data-tt-id="a1" data-tt-parent-id="a">
37 <td>a1</td>
38 <td>a1.jsp</td>
39 <td><button>edit</button> <td>
40 </tr>
41 <tr data-tt-id="b">
42 <td>b</td>
43 <td>b.jsp</td>
44 <td><button>edit</button> <td>
45 </tr>
46 <tr data-tt-id="b1" data-tt-parent-id="b">
47 <td>b1</td>
48 <td>b1.jsp</td>
49 <td><button>edit</button> <td>
50 </tr>
51 </table>
52 </div>
53 </body>
54 </html>
2、有了上面的基础,再来看连数据库的,可动态扩展(推荐),但是相对麻烦一点。
效果图:
数据库模型是这样的:
字段解释:nodeId就是节点的id。pid是 parentId也就是父亲的id(注意:最根的节点的pid会和代码耦合,或做好约定——代码总要根据什么字符来找到最根节点),表示该节点是哪个节点的子节点。type=1代表功能,type=0代表菜单。level代表该节点在树的第几层。
我做了什么工作呢?
简单解释一下,就是通过查数据库,把上面的数据查出来,每一行数据封装成为一个节点,然后拼成一颗树,然后对树进行“中序遍历”,按“中序遍历“的顺序把每一个节点添加到list,最后显示在前台(有点绕,下面解释为什么这样做。因为是多叉树,中序遍历我打了引号)。注意:这里的数据是可以动态扩展的。
数据库查出来的数据本来就是一个list,我把这个list的数据封装成为一个节点,然后拼成一颗树,然后又把这颗树按中序的遍历顺序转化成了list。
看似多余,其实这是由于treetable这个插件构建树的时候是根据html的table里面定义的tr来构建的,具体可观察上面写死的那个例子。而它对tr定义的顺序也有要求(有兴趣可在自己机器上调换一下tr的顺序,看看效果)。
在这个前提下,试想:传会前台的数据要怎么解析?传回来的数据毫无疑问是json数据,是用list结构的还是tree结构的?
其实都可以。如果是tree结构的,前台一样需要对这一棵树进行“中序遍历“,按这个顺序把每一个节点生成一个tr。这里我是在后台处理了业务逻辑,传回来的是“中序遍历“后的list。
OK,大家应该迫不及待想要知道具体实现了.....
满足大家,先来看前端代码:
1 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
3 <html>
4 <head>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6 <title>Insert title here</title>
7 <%
8 String server_path = request.getContextPath();
9 %>
10 <script type="text/javascript" src="../bootstrap-3.3.7-dist/treeview/jquery.js"></script>
11 <script type="text/javascript" src="../js/jquery.treetable.js"></script>
12 <link rel="stylesheet" type="text/css" href="../css/jquery.treetable.css">
13 <link rel="stylesheet" type="text/css" href="../css/jquery.treetable.theme.default.css">
14 <script type="text/javascript">
15 $(document).ready(function(){
16 $.ajax({
17 "type" : 'post',
18 "url" : '<%= server_path%>/resource/reslist',
19 "dataType" : "json",
20 "success" : function(data) {
21 $.each(data.data, function(idx, obj) {
22 $("#treeTable").append("<tr data-tt-id=\"" + obj.nodeId + "\" data-tt-parent-id=\"" + obj.pid + "\"><td>" + obj.text + "</td><td>" + obj.href + "</td><td><button id=\"" + obj.nodeId + "\">编辑</button><button id=\"" + obj.nodeId + "\">删除</button></td></tr>");
23 });
24 $("#treeTable").treetable({
25 expandable : true,
26 initialState:"expanded",
27 //expandable : true
28 clickableNodeNames:true,//点击节点名称也打开子节点.
29 indent : 30//每个分支缩进的像素数。
30 });
31 }
32 });
33
34 });
35 </script>
36 </head>
37 <body>
38 <table id="treeTable" style="width:800px">
39 <tr>
40 <td>名字</td>
41 <td>URL</td>
42 <td>操作</td>
43 </tr>
44 </table>
45
46 </body>
47 </html>
注意:上面用了ajax的异步请求,要把$("#treeTable").treetable();方法写在success域里面,因为要重新生成table,必须要先有数据,然后才能生成!!!
控制器(springMVC)代码:
@RequestMapping("reslist")
public void getReslist(HttpServletRequest request,HttpServletResponse response) throws Exception{
json.setResult("no");//返回前台的json数据
Node tree = getTreeJson();//获得树形结构的json数据
Node n = tree.zxPraseTree(tree);//把树形结构数据按中序遍历顺序,加入list
List<Node> reslist = n.getNodes();//获得上面的list
List<Node> list = new ArrayList<Node>();
for(Node node : reslist) {//去掉null节点
if(null != node) {
if(node.getNodeId() != null) {
list.add(node);
}
}
}
json.setData(list);//设置,返回到前台
json.setResult("ok");
response.getWriter().println(mapper.writeValueAsString(json));
}
public Node getTreeJson() {
List<Resource> reslist = resourceService.loadAll();//从数据库加载所有数据,得到list
List<Node> nodes = new ArrayList<Node>();
for(Resource res : reslist){
Node node = new Node();
node.setHref(res.getUrl());
node.setIcon(res.getIcon());
node.setNodeId(res.getNodeId());
node.setPid(res.getPid());
node.setText(res.getName());
nodes.add(node);
}
Node tree = new Node();
Node mt = tree.createTree(nodes);//把list转化成tree
System.out.println(tree.iteratorTree(mt));//遍历打印
return mt;
}
提供一个工具类:
1 import java.util.ArrayList;
2 import java.util.List;
3 /**
4 * 树形节点模型
5 * @author chenht
6 *
7 */
8 public class Node {
9 public Node() {
10 this.nodes = new ArrayList<Node>();
11 }
12 public Node(String nodeId,String pId) {
13 this.nodeId = nodeId;
14 this.pid = pId;
15 this.nodes = new ArrayList<Node>();
16 }
17 /**
18 * 生成一个节点
19 * @param nodeId
20 * @param pId
21 * @param text
22 * @param icon
23 * @param href
24 */
25 public Node(String nodeId, String pId, String text, String icon, String href) {
26 super();
27 this.nodeId = nodeId;
28 this.pid = pId;
29 this.text = text;
30 this.icon = icon;
31 this.href = href;
32 this.nodes = new ArrayList<Node>();
33 }
34
35 private String nodeId; //树的节点Id,区别于数据库中保存的数据Id。
36 private String pid;
37 private String text; //节点名称
38 private String icon;
39 private String href; //点击节点触发的链接
40 private List<Node> nodes; //子节点,可以用递归的方法读取
41
42 public String getNodeId() {
43 return nodeId;
44 }
45 public void setNodeId(String nodeId) {
46 this.nodeId = nodeId;
47 }
48
49 public String getPid() {
50 return pid;
51 }
52 public void setPid(String pid) {
53 this.pid = pid;
54 }
55
56 public String getText() {
57 return text;
58 }
59 public void setText(String text) {
60 this.text = text;
61 }
62
63 public String getIcon() {
64 return icon;
65 }
66 public void setIcon(String icon) {
67 this.icon = icon;
68 }
69
70 public String getHref() {
71 return href;
72 }
73 public void setHref(String href) {
74 this.href = href;
75 }
76
77 public List<Node> getNodes() {
78 return nodes;
79 }
80 public void setNodes(List<Node> nodes) {
81 this.nodes = nodes;
82 }
83
84 /**
85 * 生成一颗多叉树,根节点为root
86 * @param Nodes 生成多叉树的节点集合
87 * @return NodeTree
88 */
89 public Node createTree(List<Node> Nodes) {
90 if (Nodes == null || Nodes.size() < 0)
91 return null;
92 Node root = new Node("root","0");
93 // 将所有节点添加到多叉树中
94 for (Node node : Nodes) {
95 if (node.getPid().equals("0") || node.getPid().equals("root")) {
96 // 向根添加一个节点
97 root.getNodes().add(node);
98 } else {
99 addChild(root, node);
100 }
101 }
102 return root;
103 }
104
105 /**
106 * 向指定多叉树节点添加子节点
107 * @param Node 多叉树节点
108 * @param child 节点
109 */
110 public void addChild(Node Node, Node child) {
111 for (Node item : Node.getNodes()) {
112 if (item.getNodeId().equals(child.getPid())) {
113 // 找到对应的父亲
114 item.getNodes().add(child);
115 break;
116 } else {
117 if (item.getNodes() != null && item.getNodes().size() > 0) {
118 addChild(item, child);
119 }
120 }
121 }
122 }
123
124 /**
125 * 遍历多叉树
126 * @param Node 多叉树节点
127 * @return
128 */
129 public String iteratorTree(Node Node) {
130 StringBuilder buffer = new StringBuilder();
131 buffer.append("\n");
132 if (Node != null) {
133 for (Node index : Node.getNodes()) {
134 buffer.append(index.getNodeId() + ",");
135 if (index.getNodes() != null && index.getNodes().size() > 0) {
136 buffer.append(iteratorTree(index));
137 }
138 }
139 }
140 buffer.append("\n");
141 return buffer.toString();
142 }
143
144
145 /**
146 * 遍历多叉树
147 * @param Node 多叉树节点
148 * @return
149 */
150 List<Node> node = new ArrayList<Node>();
151 public Node zxPraseTree(Node Node) {
152 if (Node != null) {
153 for (Node index : Node.getNodes()) {
154 node.add(index);
155 if (index.getNodes() != null && index.getNodes().size() > 0) {
156 node.add(zxPraseTree(index));
157 }
158 }
159 }
160 //buffer.append("\n");
161 Node n = new Node();
162 n.setNodes(node);
163 return n;
164 }
165
166 public static void main(String[] args) {
167 List<Node> nodes = new ArrayList<Node>();
168 nodes.add(new Node("系统管理", "0"));
169 nodes.add(new Node("角色管理", "系统管理"));
170 nodes.add(new Node("资源管理", "系统管理"));
171 nodes.add(new Node("用户管理", "系统管理"));
172 nodes.add(new Node("添加用户", "用户管理"));
173 nodes.add(new Node("修改用户", "用户管理"));
174 nodes.add(new Node("机票管理", "系统管理"));
175
176 Node tree = new Node();
177 Node mt = tree.createTree(nodes);
178 System.out.println(tree.iteratorTree(mt));
179 Node n = tree.zxPraseTree(mt);
180 List<Node> list = n.getNodes();
181 for(Node node : list) {
182 System.out.println(node.getNodeId());
183 }
184 }
185
186
187 }
传回来的数据:
再加上导入bootstrap的包,稍微改一下样式就是第一张图的效果啦~~~
最后再次说明:本例子支持连数据库,动态扩展。但是例子用了springMVC的环境,不可硬搬代码到你机器上去运行哦。主要思路已经写明白了,工具类也给出,已帮各位解决80%难度。主要是要明白每一步做了什么工作,事在人为,根据思路相信你也可以弄出来。