1. final 用于声明属性、方法和类,分别表示属性不可变,方法不可重写,类不可继承。
    其实可以参考用easyuitree ztree
    参考:
      https://www.jstree.com/demo/
      https://www.jstree.com/plugins/
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  7. <meta name="viewport" content="width=device-width, initial-scale=1">
  8. <title>菜单配置页面</title>
  9. <!-- css代码 -->
  10. <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
  11. <!-- <link rel="stylesheet" type="text/css" href="/css/default/style.min.css"> -->
  12. <style type="text/css">
  13. .demo {
  14. width: 250px;
  15. margin: 0 17px 17px 0;
  16. float: left;
  17. border: 1px solid #ebebeb;
  18. height: 197px;
  19. }
  20.  
  21. .last {
  22. margin-right: 0;
  23. }
  24. </style>
  25. <!-- 引入外部js -->
  26. <script type="text/javascript" src="/js/fe/jquery-2.1.4.min.js"></script>
  27. <script type="text/javascript" src="/js/fe/bootstrap.min.js"></script>
  28. <script type="text/javascript" src="/js/fe/jquery.jstree.js"></script>
  29. <script type="text/javascript" src="/js/fe/jquery.hotkeys.js"></script>
  30. <script type="text/javascript" src="/js/fe/jquery.cookie.js"></script>
  31. <script type="text/javascript" src="/js/fe/jstree.min.js"></script>
  32. <!-- js代码 -->
  33. <script type="text/javascript">
  34. // jQuery(document).ready(function() {
  35.  
  36. $(function() {
  37. var selectRole = "";
  38. // 初始化jstree
  39. $("#menuTreeContainer").jstree({
  40. "core": {
  41. "strings": {
  42. loading: "Loading ..."
  43. }
  44. },
  45. "json_data": {
  46. "ajax": {
  47. "dataType": 'json',
  48. // 使用ajax加载数据,如果和data同时使用则只在打开未加载的子节点时起作用
  49. "url": "/config/queryAllMenuNodes.json",
  50. "async": false,
  51. "success": function(data) {
  52. if (data.success) {
  53. return _callBack(data.content);
  54. }
  55. }
  56. }
  57. },
  58. "ui" : {
  59. "initially_select" : []
  60. },
  61. "themes": {
  62. "icons": false
  63. },
  64. "plugins": ["themes", "json_data", "ui","search"]
  65. })
  66. .bind("loaded.jstree", function(e, data) {
  67. //初始打开第一个叶子节点所在目录
  68. $("#menuTreeContainer").jstree("open_all");
  69. })
  70. .bind("select_node.jstree", function(e, data) {
  71. $("#currentPath").val(data.rslt.obj.data("path"));
  72. $("#currentNode_id").val(data.rslt.obj.data("id"));
  73. $("#currentNode_name").val(data.rslt.obj.data("name"));
  74. $("#currParentPath").val(data.rslt.obj.data("parentPath"));
  75. });
  76.  
  77. });
  78.  
  79. // });
  80.  
  81. function _callBack(data) {
  82. var res = [],
  83. expIds = [],
  84. attr = {};
  85. jQuery.each(data, function(i) {
  86. var childData = data[i].children;
  87. if (!childData || jQuery.trim(childData).length == 0) {
  88. childData = "";
  89. }
  90. // var state = "open";
  91. var href = "";
  92. var image = "";
  93. res.push({
  94. "attr": {
  95. "id": data[i].id
  96. },
  97. "data": {
  98. "title": data[i].name
  99. },
  100. "children": _callBack(data[i].children),
  101. "metadata": {
  102. "id": data[i].id,
  103. "name": data[i].name,
  104. "parentId": data[i].parentId,
  105. "path": data[i].path,
  106. "parentPath": data[i].parentPath
  107. },
  108. // "state": state,
  109. "icon": image
  110. });
  111.  
  112. });
  113.  
  114. return res;
  115. };
  116.  
  117. function menuCreate() {
  118. var ref = $('#menuTreeContainer').jstree(true),
  119. sel = ref.get_selected();
  120. if (!sel.length) {
  121. return false;
  122. }
  123. sel = sel[0];
  124. sel = ref.create_node(sel, {
  125. "type": "file"
  126. });
  127. if (sel) {
  128. ref.edit(sel);
  129. }
  130. };
  131.  
  132. function menuRename() {
  133. var ref = $('#menuTreeContainer').jstree(true),
  134. sel = ref.get_selected();
  135. if (!sel.length) {
  136. return false;
  137. }
  138. sel = sel[0];
  139. ref.edit(sel);
  140. };
  141.  
  142. //打开/关闭所有节点
  143. var openAllNode = function(e) {
  144. $("#menuTreeContainer").jstree("open_all");
  145. }
  146.  
  147. var hideAllNode = function(e) {
  148. $("#menuTreeContainer").jstree("close_all");
  149. }
  150.  
  151. function showParentPath() {
  152. jQuery.ajax({
  153. dataType: 'json',
  154. type: 'POST',
  155. async: false,
  156. url: 'getMenuParentPath.json',
  157. data: param,
  158. success: function(data) {
  159. if (data.success) {
  160. _.each(data.content, function(v) {
  161. jQuery("select[name=add-columnsecuritylevel-select]").append("<option value='" + v.code + "'>" + v.code + "</option>");
  162. jQuery("select[name=modify-columnsecuritylevel-select]").append("<option value='" + v.code + "'>" + v.code + "</option>");
  163. });
  164. } else {
  165. alert(data.message);
  166. }
  167. }
  168. });
  169. }
  170.  
  171. var modifyMenu = function() {
  172.  
  173. var nodeParentPath = $("#currParentPath").val(),
  174. nodeParentId=$("#currentNode_id").val(),
  175. nodeName=$("#currentNode_name").val();
  176.  
  177. $("#nodeOpera_parentId").val($("#currentNode_id").val());
  178. $("#nodeOpera_parentPath").val($("#currentPath").val());
  179.  
  180. jQuery.ajax({
  181. dataType: 'json',
  182. type: 'POST',
  183. url: 'modifyMenuTree.json',
  184. data: {
  185. "nodeParentId":nodeParentId,
  186. "nodeName":nodeName,
  187. "nodeParentPath":nodeParentPath,
  188. "type":"type"
  189. },
  190. success: function(data) {
  191. if (data.success) {
  192. alert("修改成功");
  193. } else {
  194. alert(data.message);
  195. }
  196. }
  197. });
  198. };
  199.  
  200. var delMenuNode = function() {
  201.  
  202. var nodeId=$("#currentNode_id").val();
  203.  
  204. jQuery.ajax({
  205. dataType: 'json',
  206. type: 'POST',
  207. url: 'delMenuNode.json',
  208. data: {
  209. "nodeId":nodeId,
  210. },
  211. success: function(data) {
  212. if (data.success) {
  213. $("#menuTreeContainer").jstree("close_all");
  214. $("#menuTreeContainer").jstree("open_all");
  215. alert("删除成功");
  216.  
  217. } else {
  218. alert(data.message);
  219. }
  220. }
  221. });
  222. };
  223.  
  224. var addSubNode = function() {
  225.  
  226. $("#nodeOpera_path").val($("#currentPath").val() +"-"+ $("#nodeOpera_name").val());
  227. $("#nodeOpera_parentPath").val($("#currentPath").val());
  228. var nodeName = $("#nodeOpera_name").val();
  229. var nodeParentId = $("#currentNode_id").val();
  230. var nodePath=$("#nodeOpera_path").val();
  231. var parentPath = $("#nodeOpera_parentPath").val();
  232. alert("nodeName"+nodeName);
  233. alert("nodeParentId"+nodeParentId);
  234. alert("nodePath"+nodePath);
  235. alert("parentPath"+parentPath);
  236.  
  237. jQuery.ajax({
  238. dataType: 'json',
  239. type: 'POST',
  240. url: 'addMenuSubNode.json',
  241. data: {
  242. "nodeName":nodeName,
  243. "nodeParentId":nodeParentId,
  244. "nodePath":nodePath,
  245. "parentPath":parentPath
  246. },
  247. success: function(data) {
  248. if (data.success) {
  249. $("#menuTreeContainer").jstree("close_all");
  250. $("#menuTreeContainer").jstree("open_all");
  251. alert("增加子目录成功");
  252.  
  253. } else {
  254. alert(data.message);
  255. }
  256. }
  257. });
  258. };
  259.  
  260. var setValue = function(){
  261. var nodeName = jQuery("#nodeOpera_name").val();
  262. jQuery("#nodeOpera_parentPath").val(tableName);
  263. }
  264.  
  265. var addRootNode = function() {
  266.  
  267. $("#nodeOpera_parentId").val("0");
  268. $("#nodeOpera_parentPath").val("菜单");
  269.  
  270. $("#nodeOpera_path").val($("#nodeOpera_name").val());
  271. var nodeName = $("#nodeOpera_name").val();
  272. var nodeParentId = $("#nodeOpera_parentId").val();
  273. var nodePath=$("#nodeOpera_path").val();
  274. var parentPath = $("#nodeOpera_parentPath").val();
  275.  
  276. if(!nodeName || jQuery.trim(nodeName).length == 0) {
  277. alert("节点名称不能为空");
  278. return;
  279. }
  280.  
  281. jQuery.ajax({
  282. dataType: 'json',
  283. type: 'POST',
  284. url: 'addMenuRootNode.json',
  285. data: {
  286. "nodeName":nodeName,
  287. "nodeParentId":nodeParentId,
  288. "nodePath":nodePath,
  289. "parentPath":parentPath
  290. },
  291. success: function(data) {
  292. if (data.success) {
  293. $("#menuTreeContainer").jstree("close_all");
  294. $("#menuTreeContainer").jstree("open_all");
  295. alert("增加根目录成功");
  296.  
  297. } else {
  298. alert(data.message);
  299. }
  300. }
  301. });
  302.  
  303. }
  304.  
  305. var searchMenu = function(e) {
  306. var searchContent = $("#treeSearchInput").val();
  307. alert("条件:" + searchContent);
  308. $("#menuTreeContainer").jstree("search",searchContent);
  309. };
  310.  
  311. </script>
  312. </head>
  313.  
  314. <body>
  315. <!-- HTML布局 -->
  316. <div class="main-container warp">
  317. <div class="col-md-4 col-sm-8 col-xs-8" style="float:bottom">
  318. <button type="button" class="btn btn-success btn-sm" onclick="menuCreate();">Create</button>
  319. <button type="button" class="btn btn-warning btn-sm" onclick="menuRename();">Rename</button>
  320. <button type="button" class="btn btn-danger btn-sm" onclick="menuDelete();"> Delete</button>
  321. </div>
  322. <div>
  323. <form onsubmit="return false">
  324. <input id="treeSearchInput" type="search" maxlength="20" class="input-medium search-query" />
  325. <input id="SearchSubmit" class="btn" type="submit" onclick ="searchMenu()" value="搜索" />
  326. </form>
  327. </div>
  328. <div id="menuTreeContainer" class="fh-leftList demo last" style="font-size:15px;backgroud: #ffffff"></div>
  329. </div>
  330. <div class="span8" style="float:left">
  331. <form class="form-horizontal">
  332. <div class="control-group">
  333. <div id="nodeOpera_buttons" class="controls">
  334. <input type="button" class="btn" id="nodeOpera_add_root" onclick="addRootNode()" value="新增根目录" />
  335. <input type="button" class="btn" id="nodeOpera_add_sub" onclick="addSubNode()" value="新增子目录" />
  336. <input type="button" class="btn" id="nodeOpera_modify" onclick="modifyMenu()" value="保存修改" />
  337. <input type="button" class="btn" id="nodeOpera_delete" onclick="delMenuNode()" value="删除目录" />
  338. <input type="button" class="btn" onclick="openAllNode()" value="全部展开" />
  339. <input type="button" class="btn" onclick="hideAllNode()" value="全部隐藏" />
  340. </div>
  341. </div>
  342. <div id="currentNode" style="">
  343. <input type="hidden" id="currentNode_parentId" />
  344. <div class="control-group">
  345. <p style="font-size: 20px;color: red;" class="controls validateTips" id="validateTips_modify"></p>
  346. </div>
  347. <div class="control-group">
  348. <label class="control-label">序号</label>
  349. <div class="controls">
  350. <input type="text" id="currentNode_id" readonly="readonly" maxlength="9" />
  351. </div>
  352. </div>
  353. <div class="control-group">
  354. <label class="control-label">名称</label>
  355. <div class="controls">
  356. <input type="text" id="currentNode_name" maxlength="20" />
  357. </div>
  358. </div>
  359. <div class="control-group">
  360. <label class="control-label">挂载菜单点</label>
  361. <div class="controls">
  362. <input type="text" id="currParentPath" maxlength="20" />
  363. </div>
  364. </div>
  365. <div class="control-group">
  366. <label class="control-label">当前路径</label>
  367. <div class="controls">
  368. <input type="text" id="currentPath" maxlength="20" />
  369. </div>
  370. </div>
  371. </div>
  372. </form>
  373.  
  374. <div id="nodeOpera_data" style="">
  375. <!-- <input type="hidden" id="nodeOpera_parentId" />
  376. <p class="validateTips" id="validateTips_add" style="color: red;"></p> -->
  377. <label>父节点ID</label><input type="text" id="nodeOpera_parentId" maxlength="500" /><br>
  378. <label>父节点路径</label><input type="text" id="nodeOpera_parentPath" onlyNumber="true" maxlength="9" /><br>
  379. <label>名称</label><input type="text" id="nodeOpera_name" onkeyup="setValue()"/><br>
  380. <label>所在路径</label><input type="text" id="nodeOpera_path" maxlength="20" /><br>
  381.  
  382. </div>
  383.  
  384. </div>
  385. </div>
  386. </body>
  387.  
  388. </html>

后台构造函数

  1. private List<TreeKey> convertTree(List<MdMenuTree> rst) {
  2. List<TreeKey> treeAttrs = new ArrayList<TreeKey>();
  3. for (MdMenuTree menuTree : rst) {
  4. TreeKey node = new TreeKey();
  5. node.setId(menuTree.getId());
  6. node.setName(menuTree.getName());
  7. node.setParentPath(menuTree.getParentPath());
  8. node.setParentId(menuTree.getParentId());
  9. node.setPath(menuTree.getPath());
  10. treeAttrs.add(node);
  11. }
  12. return treeAttrs;
  13. }
  14.  
  15. private List<TreeKey> loadTree(List<TreeKey> treeAttrs, long parentId) {
  16.  
  17. List<TreeKey> nodeList = new ArrayList<TreeKey>();
  18. for (TreeKey node2 : treeAttrs) {
  19. if ((parentId == node2.getParentId())) {
  20. List<TreeKey> childNodes = loadTree(treeAttrs, node2.getId());
  21. node2.setChildren(childNodes);
  22. nodeList.add(node2);
  23. }
  24. }
  25.  
  26. return nodeList;
  27. }

 

踩过的坑

会无线循环下去,我的初步想法是去掉那个虚线的图标,或者在虚线那个“+”和“-”上加个控制事件,但是,这个办法行不通

解决答案: 

根节点有 state='closed' 属性。

去掉那个state="closed"(注意,改成open是不行的),否则这个节点会被视为还有子节点,jstree会再次调用你的ajax配置的url以加载子节点的数据。 你也可以修改你的url的服务器实现,根据父节点的id返回不同的元素以实现逐级打开的效果。 并设置correct_state标志以实现节点状态的自动更正。

correct_state属性:

  如果设定为true,对于ajax返回的空的反馈结果,将被转换为子节点,而不再显示为打开样式。

jstree树形菜单的更多相关文章

  1. jsTree树形菜单分类

    这里我演示的jsTree是基于ABP框架 ,展示部分代码,话不多说首先看效果如: 1:引入JS <link href="/jstree/themes/default/style.css ...

  2. 实用的树形菜单控件tree

     jQuery plugin: Treeview  这个插件能够把无序列表转换成可展开与收缩的Tree. jQuery plugin: Treeview  jQuery  jstree  jsTree ...

  3. html树形菜单控件

    html树形菜单控件  链接 http://www.ithao123.cn/content-713974.html         jQuery plugin: Treeview  这个插件能够把无序 ...

  4. 在Bootstrap开发框架中使用bootstrapTable表格插件和jstree树形列表插件时候,对树列表条件和查询条件的处理

    在我Boostrap框架中,很多地方需要使用bootstrapTable表格插件和jstree树形列表插件来共同构建一个比较常见的查询界面,bootstrapTable表格插件主要用来实现数据的分页和 ...

  5. 【转】html树形菜单控件

    Query plugin: Treeview  这个插件能够把无序列表转换成可展开与收缩的Tree. 主页:http://bassistance.de/jQuery-plugins/jquery-pl ...

  6. jQuery 树形菜单

    树形菜单 在 jQuery easyu中其左侧的主菜单使用的是 easyui 中的 tree 组件,不是太熟悉,不过感觉不是太好用. 比如 easyui 中的 tree 需要单击分叉节点前的小三角,才 ...

  7. JS树形菜单

    超全的JS树形菜单源代码共享(有实例图) 树形菜单是很常用的效果,常用在管理软件当中,但是一套树形菜单已经不能满足需求,所以如果能有一套比较全面的树形菜单JS特效代码,将会非常方便,下面懒人萱将超全的 ...

  8. 简单实用的二级树形菜单hovertree

    原创 hovertree是一个仿京东的树形菜单jquery插件,暂时有银色和绿色两种. 官方网址:http://keleyi.com/jq/hovertree/欢迎下载使用 查看绿色效果:http:/ ...

  9. Vue.js 递归组件实现树形菜单

    最近看了 Vue.js 的递归组件,实现了一个最基本的树形菜单. 项目结构: main.js 作为入口,很简单: import Vue from 'vue' Vue.config.debug = tr ...

随机推荐

  1. 【转】Robust regression(稳健回归)

    Robust regression(稳健回归) 语法 b=robustfit(X,y) b=robustfit(X,y,wfun,tune) b=robustfit(X,y,wfun,tune,con ...

  2. spring之p命名空间注入

    <bean id="personId" class="com.itheima.f_xml.c_p.Person" p:pname="禹太璞&qu ...

  3. 网易云免费OSS服务用做Markdown图床或博客图片外链

    我使用据说是Windows下最好用的Markdown编辑器“MarkdownPad2”(个人感觉还是Visual Code+Markdown插件666)写Markdown,在贴图方面遇到一个问题,于是 ...

  4. python中的协程及实现

    1.协程的概念: 协程是一种用户态的轻量级线程.协程拥有自己的寄存器上下文和栈. 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回来的时候,恢复先前保存的寄存器上下文和栈. 因此,协程能保留 ...

  5. python中的函数对象与闭包函数

    函数对象 在python中,一切皆对象,函数也是对象 在python语言中,声明或定义一个函数时,使用语句: def func_name(arg1,arg2,...): func_suite 当执行流 ...

  6. 弥补wxpython无背景图片缺陷

    思路: 通过设置Panel的背景样式为wx.BG_STYLE_CUSTOM: self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) 绑定Panel的背景事情: sel ...

  7. 51NOD 1705 七星剑 [DP 期望的线性性质]

    传送门 题意: 七颗星,第$i$课星用第$j$个宝石有$p[i][j]$的概率成功,失败将为$g[i][j]$颗星: 第$j$个宝石化费$c[j]$ 求最小期望化费 $MD$本来自己思路挺对的看了半天 ...

  8. POJ 2007 Scrambled Polygon [凸包 极角排序]

    Scrambled Polygon Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 8636   Accepted: 4105 ...

  9. C# 使用反射获取界面并传参

    // 通过反射创建类库中的实例 try { // 通过反射,获取模块 Assembly assembly = Assembly.LoadFrom(AppDomain.CurrentDomain.Bas ...

  10. 关于@Override

    首先,来了解一下“重载”和“覆写”的区别: 重载: (1)方法重载是让类以统一的方式处理不同类型数据的一种手段.多个同名函数同时存在,具有不同的参数个数/类型.重载Overloading是一个类中多态 ...