1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>js Tree Test</title> 13 14 <meta http-equiv="pragma" content="no-cache"> 15 <meta http-equiv="cache-control" content="no-cache"> 16 <meta http-equiv="expires" content="0"> 17 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 18 <meta http-equiv="description" content="This is my page"> 19 <!-- 20 <link rel="stylesheet" type="text/css" href="styles.css"> 21 --> 22 <!-- CSS for js tree --> 23 <link rel="stylesheet" type="text/css" href="static/jstree/dist/themes/default/style.min.css"> 24 <link rel="stylesheet" type="text/css" href="static/jstree/dist/themes/default-dark/style.min.css"> 25 <!-- CSS for bootstrap --> 26 <link rel="stylesheet" type="text/css" href="static/bootstrap4.0/css/bootstrap.min.css"> 27 28 <!-- JS for jQuery --> 29 <script type="text/javascript" src="static/js/jquery.min.js"></script> 30 <!-- JS for js tree --> 31 <script type="text/javascript" src="static/jstree/dist/jstree.min.js"></script> 32 <!-- JS for bootstrap --> 33 <script type="text/javascript" src="static/bootstrap4.0/js/bootstrap.min.js"></script> 34 </head> 35 36 <body> 37 <div> 38 <ul class="nav nav-tabs" role="tablist"> 39 <li role="presentation" class="active"><a href="#">Home</a></li> 40 <li role="presentation"><a href="#">Profile</a></li> 41 <li role="presentation"><a href="#">Messages</a></li> 42 </ul> 43 </div> 44 <div class="panel panel-default"> 45 <div class="panel-body"> 46 <div class="tree" id="jstree"></div> 47 </div> 48 </div> 49 50 51 <script> 52 $(function(){ 53 $('#jstree').jstree({ 54 core : { 55 check_callback : true, 56 data : [ 57 { "id" : "1", "parent" : "#", "text" : "root"}, 58 { "id" : "2", "parent" : "1", "text" : "child 1" }, 59 { "id" : "3", "parent" : "1", "text" : "child 2"}, 60 { "id" : "4", "parent" : "1", "text" : "child 3" }, 61 { "id" : "5", "parent" : "1", "text" : "child 4" }, 62 { "id" : "6", "parent" : "1", "text" : "child 5" }, 63 { "id" : "7", "parent" : "1", "text" : "child 6"}, 64 { "id" : "8", "parent" : "3", "text" : "child 3-1" }, 65 { "id" : "9", "parent" : "3", "text" : "child 3-2" }, 66 { "id" : "10", "parent" : "3", "text" : "child 3-3"} 67 ], 68 }, 69 plugins : ["wholerow","checkbox"] 70 }).on("ready.jstree", function (e, data) { 71 //data.instance.open_all(); 72 }).bind("loaded.jstree",function(e,data){ 73 var checkId=[9]; 74 jQuery('#jstree').jstree("open_all"); 75 jQuery('#jstree').find("li").each(function(){ 76 if(checkId == 'all'){ 77 jQuery('#jstree').jstree("check_node",jQuery(this)); 78 }else if(checkId instanceof Array){ 79 for(var i=0;i<checkId.length;i++){ 80 if(jQuery(this).attr("id") == checkId[i]){ 81 jQuery('#jstree').jstree("check_node",jQuery(this)); 82 } 83 } 84 } 85 }); 86 }); 87 }); 88 </script> 89 </body> 90 </html>
一丶
1.该checkbox并不是真正的input-type='checkbox',而是图片,可以在jstree的包中看到这个图片,这也是比较通用的方式。
2.该页面放在SSM架构中实现的显示,在配置静态文件的时候遇到了一个问题:无法加载32.png和.gif文件
于是在web.xml文件分发器的前面加入了如下的配置:
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.png</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.gif</url-pattern> </servlet-mapping>
网上有几种关于静态文件的加入方法,这种配置方法看起来有一些麻烦。把常用的后缀配置出来也还行。不想要的直接过滤掉。
二丶构建树的两种方式:
方式1:使用id,parent,text,icon等给出树的列表,parent节点将id设置为#
缺点:id和parent均必须唯一,不能有重复的key出现,如果重复,在使用plugins-checkbox时会出现错误勾选的情况。
方式2:使用text,children{}显示的把树形结构给出来,可以不设置id和parent,自动根据children的关系生成树。
缺点:需要根据数据库中的id和parent关系,在后台自己写嵌套方法或者递归将树形结构生成
结构如下:
为何不和方式1冲突,此处id和parent的命名不要出现
1 package com.ws.poi.user; 2 3 /** 4 * @author Administrator 5 * 6 */ 7 public class JsTreeVo { 8 private int keyId; 9 private int pId; 10 private String text; 11 private String icon; 12 private JsTreeVo children; 13 private LiAttr liattr; 14 // private TreeState{opened:true,selected:true,disabled,true} TODO 15 public int getKeyId() { 16 return keyId; 17 } 18 public void setKeyId(int keyId) { 19 this.keyId = keyId; 20 } 21 public int getpId() { 22 return pId; 23 } 24 public void setpId(int pId) { 25 this.pId = pId; 26 } 27 public String getText() { 28 return text; 29 } 30 public void setText(String text) { 31 this.text = text; 32 } 33 public String getIcon() { 34 return icon; 35 } 36 public void setIcon(String icon) { 37 this.icon = icon; 38 } 39 public JsTreeVo getChildren() { 40 return children; 41 } 42 public void setChildren(JsTreeVo children) { 43 this.children = children; 44 } 45 public LiAttr getLiattr() { 46 return liattr; 47 } 48 public void setLiattr(LiAttr liattr) { 49 this.liattr = liattr; 50 } 51 52 53 } 54 class LiAttr{ 55 private int pId; 56 // TODO 其他 li的自定义属性 -同理 a_li属性也可以定义一个类来管理 57 }
生成List<JsTreeVo> treeList即可:结构需要自己写方法生成。
PS:checkbox已经占用了click_node.jstree,dbclick_node.jstree,change_node事件
如果需要处理checkbox被勾选和反选,可以使用这两个事件:
select_node.jstree(e,data)和deselect_node.jstree(e,data)来获取被选中和反选的节点
e.树对象,可以拿到这棵树的所有内容
data.树数据,也可以拿到树的内容
可以通过data.instance.get_selected();获取到当前被选中的行的id,然后做进一步的处理,这些只要有一定jquery和js基础的都能做到。
三丶一些技巧
1.使用浏览器的console.log打印树的结构
2.open_all方法有弊端,如果数据量比较大,树形结构比较大的时候不建议使用这个方法。这个方法效率不高。
可以使用get_selected和get_node(node)方法拿到这个节点写一个递归方法来展开需要展开的节点:open_node(node);
3.关闭树可以直接使用close_all
4.使用checkbox-plugins时,一方面是事件的冲突性,另外一方面是数据回显时比较搞笑:如果last_child_node没有被展开是无法通过get_checked()方法来获取这个选中节点的
此时就需要借助1.2.的建议写方法来展开指定节点再抓取选中的值,不要直接使用open_all方法。
5.其他的一些常用操作,多学习js和jquery类似的插件都可以很好的解决。
6.树形结构是有层次的,4.中无法直接通过get_checked方法获取勾选的节点的根本原因就如此。使用open_node的时候也是需要递归展开节点,从root到末尾children。
7.通过get_bottom_checked()方法获取未展开却被勾选了的子末尾节点。
8.是否可以通过,get_parent和get_children回显数据呢?
没有get_children方法,可以使用:
$("#jstree2").jstree(true).get_node("j2_3"),该方法可以获取到未展开的节点。
$("#jstree2").jstree(true).get_node("j2_2").children_d,该方法能拿到该节点下的所有子节点,不区分层级。
由于树形结构未展开,所以是无法从children_d中直接获取到html的dom对象。
但是,可以拿到每一层的文本内容,可以先将这部分文本内容保存起来,找到需要勾选的节点,在open操作的时候把这些id选中。
下面成功绕过了手动调用open_node、open_all方法:
1 $('#jstree2').jstree({ 2 core : { 3 check_callback : true, 4 data : [ 5 { "text" : "root"}, 6 { "text" : "A","children":[{ "text" : "A-1","children":[{ "text" : "A-1-1" },{ "text" : "A-1-2"}]},{ "text" : "A-2","children":[{ "text" : "A-2-1" },{ "text" : "A-2-2"}]}] }, 7 { "text" : "child 2"}, 8 { "text" : "child 3","children":[{ "text" : "child 5" },{ "text" : "child 6"}]}, 9 { "text" : "child 4","children":[{ "text" : "child 5" },{ "text" : "child 6"}]}, 10 { "text" : "child 5" }, 11 { "text" : "child 6"}, 12 { "text" : "child 3-1" }, 13 { "text" : "child 3-2" }, 14 { "text" : "child 3-3"} 15 ], 16 }, 17 plugins : ["wholerow","checkbox"] 18 }).on("ready.jstree", function (e, data) { 19 //data.instance.open_all(); 20 }).bind("loaded.jstree",function(e,data){ 21 22 /** 以下操作成功避开了手动调用open_node方法*/ 23 24 // 测试数据 - 需要回显的数据结构 25 var check = ['A/A-1/A-1-2','A/A-2/A-2-1']; 26 27 // 所有节点id列表 28 var nodes = data.instance._model.data; 29 //console.log(nodes); 30 31 var $tree = $("#jstree2").jstree(true); 32 var p_length = 0; 33 var rv = ""; 34 var val = ""; 35 var node_id = ""; 36 37 for(var i in check){ 38 39 val = check[i]; 40 41 $.each(nodes,function(index,element){ 42 43 node_id = index; 44 p_length = $tree.get_node(node_id).parents.length; 45 46 // 过滤掉不足3层的节点 47 if(p_length==3){ 48 49 var p_2 = $tree.get_parent(node_id); 50 var p_1 = $tree.get_parent(p_2); 51 52 // 1.2.3层文本 53 rv = $tree.get_node(p_1).text 54 + "/" + $tree.get_node(p_2).text 55 + "/" + $tree.get_node(node_id).text; 56 57 // 过滤掉不满足条件的文本 58 if(rv==val){ 59 //console.log(rv); 60 // TODO 以下操作能选上,但是却无法将父节点半选 61 //$tree.get_node(node_id).state.selected=true; 62 63 // 调用check_node方法勾选满足条件的文本 64 $("#jstree2").jstree("check_node",node_id); 65 } 66 } 67 }); 68 } 69 70 });
下面是两种实现的效果图:
四丶关于异步
后续补充
五丶关于添加菜单操作
后续补充
本文代码量太少,工作性质约束,没办法把代码搬迁过来,如有疑问,欢迎评论交流。