Tree:
easyui tree的异步加载实现很简单,easyui的中文API文档中有实例(http://api.btboys.com/easyui/)——创建异步树形菜单,就是在tree node 元素中要有一个id属性,同时还需要state的属性(state为'closed'的时候,点击节点时会自动请求,并且将id作为参数Post到后台),只加载一次。
远程异步加载:
http://www.cnblogs.com/CoreCaiNiao/archive/2010/08/20/1804387.html
$(function(){ $('#tt2').tree({ checkbox: false, url: '/common/GetGoupJsonByPid.ashx?pid=0', onBeforeExpand:function(node,param){ $('#tt2').tree('options').url = "/common/GetGoupJsonByPid.ashx?pid=" + node.id; //只加载一次。 }, onClick:function(node){ alert(node.id); } }); });
例子:
JSP:
<script type="text/javascript" src="<%=request.getContextPath()%>/js/app/sysManagement/sysMenu.js" charset="UTF-8"></script> <html> <style> #editForm{} #editForm input{width:300px;} #editForm select{width:300px;} </style> <body> <div id="treeMenu" class="easyui-menu" style="width:120px;"></div> <div class="easyui-layout" data-options="fit:true,border:false" style="width: 100%; height: 100%;"> <div data-options="region:'north',border:false,title:'菜单管理', iconCls: 'icon-tip'" style="height:55px"> <div id="toolbar" class="easyui-toolbar" style="margin-top:5px;"> <a class="easyui-linkbutton" data-options="plain: true, iconCls: 'ope-add'" onclick="javascript:addBrothers()">新增同级</a> <a class="easyui-linkbutton" data-options="plain: true, iconCls: 'ope-add'" onclick="javascript:addChildren();">新增下级</a> <a class="easyui-linkbutton" data-options="plain: true, iconCls: 'ope-remove'" onclick="javascript:removeMenu();">删除</a> <a class="easyui-linkbutton" data-options="plain: true, iconCls: 'ope-save'" onclick="javascript:saveOrUpdateMenu();">保存</a> </div> </div> <div data-options="region:'center',border:false" > <div class="easyui-layout" data-options="fit:true,border:false" style="width: 100%; height: 100%;"> <div region="west" data-options="split:true,border:true,minWidth: 150, maxWidth: 500" style="width:230px;"> <ul id="tree"></ul> </div> <div data-options="region:'center',border:false" > <div style="margin:5px;"> <form name="editForm" method="post" id="editForm" class="easyui-SuperEditForm"> <input id="id" name="id" type="hidden"/> <input id="supId" name="supId" type="hidden"/> <table class="tableForm_L" width="100%" border="0" cellpadding="0" cellspacing="1"> <tr> <th width="15%"> 菜单名 <span class="red">*</span> </th> <td width="85%"> <input type="text" name="menuName" id="menuName" class="easyui-validatebox" data-options="required:true,validType:'length[1,200]'" /> </td> </tr> <tr> <th width="15%"> 链接URL <span class="red">*</span> </th> <td width="85%"> <input type="text" name="menuUrl" id="menuUrl" class="easyui-validatebox" data-options="required:true"/> </td> </tr> <tr> <th width="15%"> 顺序ID </th> <td width="85%"> <input type="text" name="orderId" id="orderId" class="easyui-validatebox" /> </td> </tr> <tr> <th width="15%"> 是否启用 <span class="red">*</span> </th> <td width="85%"> <select id="enabledFlag" name="enabledFlag" class='easyui-combobox' data-options="required:true,panelHeight:'auto',editable:false,readonly:false"> <option value="Y">是</option> <option value="N">否</option> </select> </td> </tr> <tr> <th width="15%">备 注</th> <td colspan="3"> <textarea cols="100" rows="13" height='auto' name="remark" id="remark"></textarea> </td> </tr> </table> </form> </div> </div> </div> </div> </div> </body> </html>
sysMenu.js
var $editForm; var $tree; var hasNew = false; $(function() { $tree = $("#tree"); $editForm = $("#editForm"); $tree.tree({ url : root + 'sysMenu/listMenus.do?pid=-1', iconCls : 'icon-save', checkbox : false, lines : true, animate : true, onBeforeExpand : function(node, param) { $tree.tree('options').url = root + "sysMenu/listMenus.do?pid=" + node.id; // 只加载一次 }, onLoadSuccess : function(node, data) { }, onSelect : function(node) { if (node.id == -1) return; if(node.id.indexOf('newNode') != -1){ var pidStr = node.id; var pid = pidStr.split("newNode")[1]; $editForm.find("input").val(""); $("#supId").val(pid); $("#remark").val("").text(""); $("#menuName").val(node.text); }else{ $tree.tree('expand',node.target) getMenuDetail(node.id); } } }); }); function getMenuDetail(id){ $.ajax({ url: root + "sysMenu/getMenuDetail.do?id="+id, type: "GET", dataType: "json", async:false, success: function (data, textStatus, XMLHttpRequest) { if(data != null){ $("#id").val(data.id); $("#supId").val(data.supId); $("#menuName").val(data.menuName); $("#menuUrl").val(data.menuUrl); $("#orderId").val(data.orderId); $('#enabledFlag').combobox('setValue', data.enabledFlag); $("#remark").val(data.remark).text(data.remark); }else{ $.messager.alert('提示','获取菜单详情失败!','error'); } } }); } function saveOrUpdateMenu(){ if (!$editForm.form('validate')) return; var selected = $tree.tree('getSelected'); if(selected == null) $.messager.alert('提示','请选择一个节点','info'); var formData=$editForm.serializeArray(); var sysMenu = {}; $.each(formData,function(i,field){ sysMenu[field.name] = field.value; }); $.ajax({ url:root+'sysMenu/saveOrUpdateMenu.do', data: sysMenu, type: "post", async:false, success: function (data, textStatus, XMLHttpRequest) { if(data != null){ $.messager.alert('提示','保存成功!','info',function(){ hasNew = false; var selected = $tree.tree('getSelected'); var parent = $tree.tree('getParent',selected.target); $tree.tree('reload',parent.target); }); }else{ $.messager.alert('提示','保存失败!','error'); } } }); } function removeMenu(){ var selected = $tree.tree('getSelected'); if(selected == null){ $.messager.alert('提示','请选择一个节点','info'); return; } if(selected.id.indexOf('newNode') != -1){ $tree.tree('remove',selected.target); hasNew = false; }else{ $.messager.confirm('提示', "确认删除节点'"+selected.text+"'?", function(r){ if (r){ $.ajax({ url : root + "sysMenu/removeMenu.do?id="+selected.id, type: 'GET', timeout: 60000, success : function(data, textStatus, jqXHR){ if('SUCCESS' == data){ hasNew = false; $tree.tree('remove',selected.target); $.messager.alert('提示','删除成功!','info'); }else{ $.messager.alert('提示','删除失败!','error'); } } }); } }); } } function addBrothers(){ if(!validate()) return; var selected = $tree.tree('getSelected'); var parent = $tree.tree('getParent',selected.target); addNewNode(parent); } function addChildren(){ if(!validate()) return; var children = $tree.tree('getSelected'); addNewNode(children); } function addNewNode(parent){ var data = {}; data.id = "newNode"+parent.id; //onSelect时的node节点不含pid,所以需要加上 data.pid = parent.id; data.text = "新建节点"; data.state = "open"; var d = new Array(); d.push(data); var param = {}; param.parent = parent.target; param.data = d; $tree.tree('append',param); var node = $tree.tree('find', data.id); $tree.tree('select', node.target); } function validate(){ var selected = $tree.tree('getSelected'); if(selected == null){ $.messager.alert('提示','请选择一个节点','info'); return false; } var text = selected.text; if(selected.id == -1){ $.messager.alert('提示','根节点不可新增节点','info'); return false; } if (selected.id.indexOf('newNode') != -1 || hasNew) { $.messager.alert("提示", "请保存或删除新增节点后再新增!", "info"); return false; } hasNew = true; return true; }
Controller:
// =================================================================菜单管理================================ @RequestMapping(value = "sysMenu/listMenus.do", method = {RequestMethod.GET,RequestMethod.POST}) @ResponseBody public List<MenuTree> listMenus(@RequestParam(required=false) long pid) { logger.debug(" listMenus begin [pid] = " + pid); List<MenuTree> result = null; try { result = sysMenuDS.listMenus(pid); } catch(Exception e) { logger.error("listMenus error :" + e.getMessage()); e.printStackTrace(); } logger.debug(" listMenus end .."); return result; } /** * 获取配额详情 * @param id * @param parentId * @return */ @RequestMapping(value = "sysMenu/getMenuDetail", method = RequestMethod.GET) @ResponseBody public SysMenu getMenuDetail(Long id) { logger.debug("getMenuDetail begin [id] = " + id); SysMenu menu = null; try { menu = sysMenuDS.getMenuDetail(id); } catch(Exception e) { logger.error("getMenuDetail error :" + e.getMessage()); e.printStackTrace(); } logger.debug("getMenuDetail end .."); return menu; } @RequestMapping(value = "sysMenu/saveOrUpdateMenu", method = RequestMethod.POST) @ResponseBody public String saveOrUpdateMenu(SysMenu menu){ logger.debug("saveOrUpdateMenu begin .."); try { sysMenuDS.saveOrUpdateMenu(menu); } catch(Exception e) { logger.error("saveOrUpdateMenu error :" + e.getMessage()); e.printStackTrace(); } logger.debug("saveOrUpdateMenu end .."); return Constants.RESULT_SUCCESS; } @RequestMapping(value = "sysMenu/removeMenu", method = RequestMethod.GET) @ResponseBody public String removeMenu(long id){ logger.debug("removeMenu begin .."); try { sysMenuDS.removeMenu(id); } catch(Exception e) { logger.error("removeMenu error :" + e.getMessage()); e.printStackTrace(); } logger.debug("removeMenu end .."); return Constants.RESULT_SUCCESS; }
Service:
@Service("iSysMenu") public class SysMenuDS implements ISysMenu { private static final Logger logger = LoggerFactory.getLogger(SysMenuDS.class); @Autowired private ISysMenuDao menuDao; /** * 菜单列表 */ @Override public List<MenuTree> listMenus(long pid) { if(pid == 0l) return new ArrayList<MenuTree>(); List<SysMenu> menus = menuDao.findByParentId(pid); List<MenuTree> trees = convertCollectionToMenuTree(menus); if(pid == -1){ trees = addRoot(trees); } return trees; } /** * 获取详情 */ @Override public SysMenu getMenuDetail(Long id) { if(id == 0l) return null; SysMenu menu = menuDao.findByMenuId(id); return menu; } /** * 保存或修改菜单 */ @Override public void saveOrUpdateMenu(SysMenu menu) { if(menu.getId() != null){ SysMenu m = menuDao.findByMenuId(menu.getId()); m.setMenuName(menu.getMenuName()); m.setMenuUrl(menu.getMenuUrl()); m.setOrderId(menu.getOrderId()); m.setEnabledFlag(menu.getEnabledFlag()); m.setRemark(menu.getRemark()); ObjectUtil.setUpdatedBy(m); menu = m; }else{ ObjectUtil.setCreatedBy(menu); } menuDao.save(menu); } @Override public void removeMenu(long id) { if(hasChildren(id)){ menuDao.deleteChildrenById(id); } menuDao.remove(id); } /** * 添加根节点 * @param children * @return */ private List<MenuTree> addRoot(List<MenuTree> children) { List<MenuTree> result = new ArrayList<MenuTree>(); MenuTree root = new MenuTree(); root.setId(String.valueOf(-1l)); root.setPid(String.valueOf(-1l)); root.setText("菜单管理"); root.setChecked(false); root.setIconCls(""); root.setState("open"); root.setChildren(children); result.add(root); return result; } public boolean hasChildren(long id){ List<SysMenu> children = menuDao.findByParentId(id); if(children != null && children.size() > 0){ return true; } return false; } public MenuTree convertToMenuTree(SysMenu menu){ MenuTree tree = new MenuTree(); tree.setId(String.valueOf(menu.getId())); tree.setPid(String.valueOf(menu.getSupId())); tree.setText(menu.getMenuName()); if(hasChildren(menu.getId())){ tree.setState("closed"); }else{ tree.setState("open"); } return tree; } public List<MenuTree> convertCollectionToMenuTree(List<SysMenu> ls){ List<MenuTree> trees = new ArrayList<MenuTree>(); if(ls == null || ls.size() == 0) return trees; for(SysMenu menu : ls){ trees.add(convertToMenuTree(menu)); } return trees; } }
相关CSS:
.icon-tip { background: url('icons/tip.png') no-repeat; } .tree-folder-open { background: url('images/tree_folder_open.gif') no-repeat; } .tree-folder { display: inline-block; background: url('images/tree_folder.gif') no-repeat; width: 16px; height: 18px; vertical-align: middle; } .tree-node-selected { background: url('images/tree_selected_bg.png') left bottom no-repeat; height: 26px; line-height: 26px; }
效果图: