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返回的空的反饋結果,將被轉換為子節點,而不再顯示為打開樣式。
