final 用于声明属性、方法和类,分别表示属性不可变,方法不可重写,类不可继承。
其实可以参考用easyui的tree 和 ztree
参考:
  https://www.jstree.com/demo/
  https://www.jstree.com/plugins/
<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>菜单配置页面</title>
<!-- css代码 -->
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
<!-- <link rel="stylesheet" type="text/css" href="/css/default/style.min.css"> -->
<style type="text/css">
.demo {
width: 250px;
margin: 0 17px 17px 0;
float: left;
border: 1px solid #ebebeb;
height: 197px;
} .last {
margin-right: 0;
}
</style>
<!-- 引入外部js -->
<script type="text/javascript" src="/js/fe/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="/js/fe/bootstrap.min.js"></script>
<script type="text/javascript" src="/js/fe/jquery.jstree.js"></script>
<script type="text/javascript" src="/js/fe/jquery.hotkeys.js"></script>
<script type="text/javascript" src="/js/fe/jquery.cookie.js"></script>
<script type="text/javascript" src="/js/fe/jstree.min.js"></script>
<!-- js代码 -->
<script type="text/javascript">
// jQuery(document).ready(function() { $(function() {
var selectRole = "";
// 初始化jstree
$("#menuTreeContainer").jstree({
"core": {
"strings": {
loading: "Loading ..."
}
},
"json_data": {
"ajax": {
"dataType": 'json',
// 使用ajax加载数据,如果和data同时使用则只在打开未加载的子节点时起作用
"url": "/config/queryAllMenuNodes.json",
"async": false,
"success": function(data) {
if (data.success) {
return _callBack(data.content);
}
}
}
},
"ui" : {
"initially_select" : []
},
"themes": {
"icons": false
},
"plugins": ["themes", "json_data", "ui","search"]
})
.bind("loaded.jstree", function(e, data) {
//初始打开第一个叶子节点所在目录
$("#menuTreeContainer").jstree("open_all");
})
.bind("select_node.jstree", function(e, data) {
$("#currentPath").val(data.rslt.obj.data("path"));
$("#currentNode_id").val(data.rslt.obj.data("id"));
$("#currentNode_name").val(data.rslt.obj.data("name"));
$("#currParentPath").val(data.rslt.obj.data("parentPath"));
}); }); // }); function _callBack(data) {
var res = [],
expIds = [],
attr = {};
jQuery.each(data, function(i) {
var childData = data[i].children;
if (!childData || jQuery.trim(childData).length == 0) {
childData = "";
}
// var state = "open";
var href = "";
var image = "";
res.push({
"attr": {
"id": data[i].id
},
"data": {
"title": data[i].name
},
"children": _callBack(data[i].children),
"metadata": {
"id": data[i].id,
"name": data[i].name,
"parentId": data[i].parentId,
"path": data[i].path,
"parentPath": data[i].parentPath
},
// "state": state,
"icon": image
}); }); return res;
}; function menuCreate() {
var ref = $('#menuTreeContainer').jstree(true),
sel = ref.get_selected();
if (!sel.length) {
return false;
}
sel = sel[0];
sel = ref.create_node(sel, {
"type": "file"
});
if (sel) {
ref.edit(sel);
}
}; function menuRename() {
var ref = $('#menuTreeContainer').jstree(true),
sel = ref.get_selected();
if (!sel.length) {
return false;
}
sel = sel[0];
ref.edit(sel);
}; //打开/关闭所有节点
var openAllNode = function(e) {
$("#menuTreeContainer").jstree("open_all");
} var hideAllNode = function(e) {
$("#menuTreeContainer").jstree("close_all");
} function showParentPath() {
jQuery.ajax({
dataType: 'json',
type: 'POST',
async: false,
url: 'getMenuParentPath.json',
data: param,
success: function(data) {
if (data.success) {
_.each(data.content, function(v) {
jQuery("select[name=add-columnsecuritylevel-select]").append("<option value='" + v.code + "'>" + v.code + "</option>");
jQuery("select[name=modify-columnsecuritylevel-select]").append("<option value='" + v.code + "'>" + v.code + "</option>");
});
} else {
alert(data.message);
}
}
});
} var modifyMenu = function() { var nodeParentPath = $("#currParentPath").val(),
nodeParentId=$("#currentNode_id").val(),
nodeName=$("#currentNode_name").val(); $("#nodeOpera_parentId").val($("#currentNode_id").val());
$("#nodeOpera_parentPath").val($("#currentPath").val()); jQuery.ajax({
dataType: 'json',
type: 'POST',
url: 'modifyMenuTree.json',
data: {
"nodeParentId":nodeParentId,
"nodeName":nodeName,
"nodeParentPath":nodeParentPath,
"type":"type"
},
success: function(data) {
if (data.success) {
alert("修改成功");
} else {
alert(data.message);
}
}
});
}; var delMenuNode = function() { var nodeId=$("#currentNode_id").val(); jQuery.ajax({
dataType: 'json',
type: 'POST',
url: 'delMenuNode.json',
data: {
"nodeId":nodeId,
},
success: function(data) {
if (data.success) {
$("#menuTreeContainer").jstree("close_all");
$("#menuTreeContainer").jstree("open_all");
alert("删除成功"); } else {
alert(data.message);
}
}
});
}; var addSubNode = function() { $("#nodeOpera_path").val($("#currentPath").val() +"-"+ $("#nodeOpera_name").val());
$("#nodeOpera_parentPath").val($("#currentPath").val());
var nodeName = $("#nodeOpera_name").val();
var nodeParentId = $("#currentNode_id").val();
var nodePath=$("#nodeOpera_path").val();
var parentPath = $("#nodeOpera_parentPath").val();
alert("nodeName"+nodeName);
alert("nodeParentId"+nodeParentId);
alert("nodePath"+nodePath);
alert("parentPath"+parentPath); jQuery.ajax({
dataType: 'json',
type: 'POST',
url: 'addMenuSubNode.json',
data: {
"nodeName":nodeName,
"nodeParentId":nodeParentId,
"nodePath":nodePath,
"parentPath":parentPath
},
success: function(data) {
if (data.success) {
$("#menuTreeContainer").jstree("close_all");
$("#menuTreeContainer").jstree("open_all");
alert("增加子目录成功"); } else {
alert(data.message);
}
}
});
}; var setValue = function(){
var nodeName = jQuery("#nodeOpera_name").val();
jQuery("#nodeOpera_parentPath").val(tableName);
} var addRootNode = function() { $("#nodeOpera_parentId").val("0");
$("#nodeOpera_parentPath").val("菜单"); $("#nodeOpera_path").val($("#nodeOpera_name").val());
var nodeName = $("#nodeOpera_name").val();
var nodeParentId = $("#nodeOpera_parentId").val();
var nodePath=$("#nodeOpera_path").val();
var parentPath = $("#nodeOpera_parentPath").val(); if(!nodeName || jQuery.trim(nodeName).length == 0) {
alert("节点名称不能为空");
return;
} jQuery.ajax({
dataType: 'json',
type: 'POST',
url: 'addMenuRootNode.json',
data: {
"nodeName":nodeName,
"nodeParentId":nodeParentId,
"nodePath":nodePath,
"parentPath":parentPath
},
success: function(data) {
if (data.success) {
$("#menuTreeContainer").jstree("close_all");
$("#menuTreeContainer").jstree("open_all");
alert("增加根目录成功"); } else {
alert(data.message);
}
}
}); } var searchMenu = function(e) {
var searchContent = $("#treeSearchInput").val();
alert("条件:" + searchContent);
$("#menuTreeContainer").jstree("search",searchContent);
}; </script>
</head> <body>
<!-- HTML布局 -->
<div class="main-container warp">
<div class="col-md-4 col-sm-8 col-xs-8" style="float:bottom">
<button type="button" class="btn btn-success btn-sm" onclick="menuCreate();">Create</button>
<button type="button" class="btn btn-warning btn-sm" onclick="menuRename();">Rename</button>
<button type="button" class="btn btn-danger btn-sm" onclick="menuDelete();"> Delete</button>
</div>
<div>
<form onsubmit="return false">
<input id="treeSearchInput" type="search" maxlength="20" class="input-medium search-query" />
<input id="SearchSubmit" class="btn" type="submit" onclick ="searchMenu()" value="搜索" />
</form>
</div>
<div id="menuTreeContainer" class="fh-leftList demo last" style="font-size:15px;backgroud: #ffffff"></div>
</div>
<div class="span8" style="float:left">
<form class="form-horizontal">
<div class="control-group">
<div id="nodeOpera_buttons" class="controls">
<input type="button" class="btn" id="nodeOpera_add_root" onclick="addRootNode()" value="新增根目录" />
<input type="button" class="btn" id="nodeOpera_add_sub" onclick="addSubNode()" value="新增子目录" />
<input type="button" class="btn" id="nodeOpera_modify" onclick="modifyMenu()" value="保存修改" />
<input type="button" class="btn" id="nodeOpera_delete" onclick="delMenuNode()" value="删除目录" />
<input type="button" class="btn" onclick="openAllNode()" value="全部展开" />
<input type="button" class="btn" onclick="hideAllNode()" value="全部隐藏" />
</div>
</div>
<div id="currentNode" style="">
<input type="hidden" id="currentNode_parentId" />
<div class="control-group">
<p style="font-size: 20px;color: red;" class="controls validateTips" id="validateTips_modify"></p>
</div>
<div class="control-group">
<label class="control-label">序号</label>
<div class="controls">
<input type="text" id="currentNode_id" readonly="readonly" maxlength="9" />
</div>
</div>
<div class="control-group">
<label class="control-label">名称</label>
<div class="controls">
<input type="text" id="currentNode_name" maxlength="20" />
</div>
</div>
<div class="control-group">
<label class="control-label">挂载菜单点</label>
<div class="controls">
<input type="text" id="currParentPath" maxlength="20" />
</div>
</div>
<div class="control-group">
<label class="control-label">当前路径</label>
<div class="controls">
<input type="text" id="currentPath" maxlength="20" />
</div>
</div>
</div>
</form> <div id="nodeOpera_data" style="">
<!-- <input type="hidden" id="nodeOpera_parentId" />
<p class="validateTips" id="validateTips_add" style="color: red;"></p> -->
<label>父节点ID</label><input type="text" id="nodeOpera_parentId" maxlength="500" /><br>
<label>父节点路径</label><input type="text" id="nodeOpera_parentPath" onlyNumber="true" maxlength="9" /><br>
<label>名称</label><input type="text" id="nodeOpera_name" onkeyup="setValue()"/><br>
<label>所在路径</label><input type="text" id="nodeOpera_path" maxlength="20" /><br> </div> </div>
</div>
</body> </html>

后台构造函数

    private List<TreeKey> convertTree(List<MdMenuTree> rst) {
List<TreeKey> treeAttrs = new ArrayList<TreeKey>();
for (MdMenuTree menuTree : rst) {
TreeKey node = new TreeKey();
node.setId(menuTree.getId());
node.setName(menuTree.getName());
node.setParentPath(menuTree.getParentPath());
node.setParentId(menuTree.getParentId());
node.setPath(menuTree.getPath());
treeAttrs.add(node);
}
return treeAttrs;
} private List<TreeKey> loadTree(List<TreeKey> treeAttrs, long parentId) { List<TreeKey> nodeList = new ArrayList<TreeKey>();
for (TreeKey node2 : treeAttrs) {
if ((parentId == node2.getParentId())) {
List<TreeKey> childNodes = loadTree(treeAttrs, node2.getId());
node2.setChildren(childNodes);
nodeList.add(node2);
}
} return nodeList;
}

 

踩过的坑

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

解决答案: 

根节点有 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. 反编译class文件并重新编译的方法

    在没有.java源码的情况下,如果想修改一个.class文件.可以通过以下步骤实现: 修改前的class文件: 一.反编译.class文件成.java文件. 1.可以使用Java Decompiler ...

  2. java 重写与重载

    一.方法重写: 参数列表必须完全与被重写方法的相同: 返回类型必须完全与被重写方法的返回类型相同: 访问权限不能比父类中被重写的方法的访问权限更低.例如:如果父类的一个方法被声明为public,那么在 ...

  3. Hibernate (三)

    1 一对多的单向 示例:一个已经存在的学生,新建一个班级,然后将该学生加入到该班级之下 设置inverse="false" <?xml version="1.0&q ...

  4. 《css定位 position》课程笔记

    这是我学习课程css定位 position时做的笔记! 本节内容 html的三种布局方式 position可选参数 z-index 盒子模型和定位的区别 侧边栏导航跟随实例 html的三种布局方式 三 ...

  5. 【转】shell学习笔记(三)——引用变量、内部变量、条件测试、字符串比较、整数比较等

    1.env显示当前的环境变量 2.PS1='[\u@\h \w \A] \$' 可以设置bash的命令与提示符. 3.echo $$ 显示当前bash的PID号 4.echo $?显示上一条指令的回传 ...

  6. 20165318 预备作业二 学习基础和C语言基础调查

    20165318 学习基础和C语言基础调查 技能学习经验 我们这一代人,或多或少的都上过各种兴趣班,舞蹈钢琴画画书法,我也是如此.可这些技能中,唯一能拿的出手的就是舞蹈了.按照<优秀的教学方法- ...

  7. Linux学习笔记一

    本文记录了Linux中常用的一些东西. 命令生效顺序 第一顺位执行绝对路径或者相对路径的命令 第二顺位执行别名 第三顺位执行Bash的内部命令 第四顺位执行按照$PATH环境变量设置定义的目录顺序的第 ...

  8. 使用FileReader实现前端预览所选图片

    需求描述 在浏览器环境下进开发网站(也就是B/S架构的应用),获取到当前设备上的图片后,希望可以在上传到服务器前简单预览一下图片内容. 具体实现 主要代码 html 部分 <input type ...

  9. c# 对象 & 类

    类定义中可以使用的访问修饰符组合 none or internal 类只能在当前工程中访问 public 类可以在任何地方访问 abstract or internal abstract 类只能在当前 ...

  10. 事件委托live,delegate,on区别

    事件委托 我们知道,DOM在为页面中的每个元素分派事件时,相应的元素一般都在事件冒泡阶段处理事件.在类似 body > div > a 这样的结构中,如果单击a元素,click事件会从a一 ...