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