jstree树形菜单
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树形菜单的更多相关文章
- jsTree树形菜单分类
这里我演示的jsTree是基于ABP框架 ,展示部分代码,话不多说首先看效果如: 1:引入JS <link href="/jstree/themes/default/style.css ...
- 实用的树形菜单控件tree
jQuery plugin: Treeview 这个插件能够把无序列表转换成可展开与收缩的Tree. jQuery plugin: Treeview jQuery jstree jsTree ...
- html树形菜单控件
html树形菜单控件 链接 http://www.ithao123.cn/content-713974.html jQuery plugin: Treeview 这个插件能够把无序 ...
- 在Bootstrap开发框架中使用bootstrapTable表格插件和jstree树形列表插件时候,对树列表条件和查询条件的处理
在我Boostrap框架中,很多地方需要使用bootstrapTable表格插件和jstree树形列表插件来共同构建一个比较常见的查询界面,bootstrapTable表格插件主要用来实现数据的分页和 ...
- 【转】html树形菜单控件
Query plugin: Treeview 这个插件能够把无序列表转换成可展开与收缩的Tree. 主页:http://bassistance.de/jQuery-plugins/jquery-pl ...
- jQuery 树形菜单
树形菜单 在 jQuery easyu中其左侧的主菜单使用的是 easyui 中的 tree 组件,不是太熟悉,不过感觉不是太好用. 比如 easyui 中的 tree 需要单击分叉节点前的小三角,才 ...
- JS树形菜单
超全的JS树形菜单源代码共享(有实例图) 树形菜单是很常用的效果,常用在管理软件当中,但是一套树形菜单已经不能满足需求,所以如果能有一套比较全面的树形菜单JS特效代码,将会非常方便,下面懒人萱将超全的 ...
- 简单实用的二级树形菜单hovertree
原创 hovertree是一个仿京东的树形菜单jquery插件,暂时有银色和绿色两种. 官方网址:http://keleyi.com/jq/hovertree/欢迎下载使用 查看绿色效果:http:/ ...
- Vue.js 递归组件实现树形菜单
最近看了 Vue.js 的递归组件,实现了一个最基本的树形菜单. 项目结构: main.js 作为入口,很简单: import Vue from 'vue' Vue.config.debug = tr ...
随机推荐
- test for python urllib
#!/usr/bin/python import urllib2 import time import logging import threading succCount = 0 failCount ...
- 李忠益TP5商城项目笔记(待完成)
商品种类的无限极分类 $data=db('goods_type')->field(['*','concat(path,",",id)'=>'paths'])->o ...
- 学会用git真的很重要
一.首先,作为一名开发人员,目前个人菜鸟一个,觉得有个仓库来管理好自己的项目是真的很重要,而目前个人认为在git上面管理自己的项目是真的很不错的推荐,接下来给大家介绍一下如何使用git上传.管理自己的 ...
- grep的小技巧
grep '^[^#]' /etc/openvpn/server.conf 中括号必须匹配一个字符^$属于标志位,不属于字符 grep没把\n看成字符 grep把空行看成^$ 还是perl的标准,空行 ...
- shell第一篇
前两天不停的再看内核相关的内容,了解内核的形成.内核的执行流程.内核的作用,结果是舍近求远. 其实我只是想了解一下shell的工作,shell与内核有关,但并不需要我么真正去做什么,至少对于我这样额初 ...
- 08_Python编码与解码
一.编码的由来 因为计算机只能处理010101二进制数据,如果要处理文本,图像,视频等,需要我们把数据转换成01010二进制格式才能被计算机处理 最先出现的是ASCII,用8位一个字节来表示,成为单字 ...
- OpenStack和Hadoop的区别
其实,OpenStack和Hadoop不是同一个层次的东西,无法比较,非要说出个区别,那就是:OpenStack是云计算管理平台,应该是属于系统级别的软件,它的主体思想是把资源进行分离,给不同的用户提 ...
- ABP官方文档翻译 3.7 领域事件(事件总线)
领域事件(事件总线) 事件总线 注入IEventBus 获取默认实例 定义事件 预定义事件 处理异常 实体更改 触发事件 处理事件 处理基础事件 处理者异常 处理多个事件 注册处理者 自动 手动 取消 ...
- [Manacher]【学习笔记】
终于填坑啦......马拉车 课件上说的好短,但是明白了,讲解稍微修改一下抄上行了,比扩展KMP好写多了 求以每个字符为中心的最长回文串的半径.如果要求可以以字符间隙为回文中心,就要在每两个字符之间及 ...
- C语言头文件中定义全局变量导致重复定义错误
合作方升级SDK后,程序编译出现变量重复定义的错误,通过错误提示无法找到什么位置重复定义了,但确定是引入新SDK后才出现的错误,从SDK的头文件中查找,最终发现在头文件中定义了全局变量 我们的项目在多 ...