二話不說,先看看效果圖:
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>
把上面代碼拷回去試試?記得導treetable的包。
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結構的(可見我另外一個例子:http://www.cnblogs.com/chenhtblog/p/8342534.html),前台一樣需要對這一棵樹進行“中序遍歷“,按這個順序把每一個節點生成一個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%難度。主要是要明白每一步做了什么工作,事在人為,根據思路相信你也可以弄出來。說實話網絡上太少比較靠譜的例子了。。。