Easyui中的Tree组件使用频率颇高,经常遇到的需求如下:

1、在树形结构上,只有叶子节点才能被选中,其他节点不能被选中;

2、在叶子节点上右键出现浮动菜单实现新增、删除、修改操作;

3、在非叶子节点上右键出现浮动菜单实现新增、修改操作。

------------------------------------------------------------------------------------------------------------------

实现方法如下:

1、搭建测试环境(可以参考前文:【原】无脑操作:IDEA + maven + SpringBoot + JPA + EasyUI实现CRUD及分页

2、建库建表

  1. DROP TABLE biz_department;
  2. CREATE TABLE biz_department
  3. (
  4. departmentid INT AUTO_INCREMENT PRIMARY KEY COMMENT '部门编号',
  5. departmentpid INT NOT NULL COMMENT '部门父编号',
  6. departmentname VARCHAR(10) NOT NULL COMMENT '部门名称'
  7. ) ENGINE=INNODB COMMENT='部门信息';
  8. INSERT INTO biz_department VALUES
  9. (NULL, 0, '总部'),
  10. (NULL, 1, '上海分公司'), (NULL, 1, '安徽分公司'),
  11. (NULL, 3, '合肥办事处'), (NULL, 3, '铜陵办事处');

3、创建实体类 Department.java

  1. @Entity
  2. @Table(name = "biz_department")
  3. public class Department {
  4. @Id
  5. @GeneratedValue(strategy = GenerationType.IDENTITY)
  6. @Column(name = "departmentid")
  7. private Integer departmentid;
  8. @Column(name = "departmentpid")
  9. private Integer departmentpid;
  10. @Column(name = "departmentname")
  11. private String departmentname;
  12.  
  13. public Department() {
  14. }
  15.  
  16. public Department(Integer departmentpid, String departmentname) {
  17. this.departmentpid = departmentpid;
  18. this.departmentname = departmentname;
  19. }
  20.  
  21. public Integer getDepartmentid() {
  22. return departmentid;
  23. }
  24.  
  25. public void setDepartmentid(Integer departmentid) {
  26. this.departmentid = departmentid;
  27. }
  28.  
  29. public Integer getDepartmentpid() {
  30. return departmentpid;
  31. }
  32.  
  33. public void setDepartmentpid(Integer departmentpid) {
  34. this.departmentpid = departmentpid;
  35. }
  36.  
  37. public String getDepartmentname() {
  38. return departmentname;
  39. }
  40.  
  41. public void setDepartmentname(String departmentname) {
  42. this.departmentname = departmentname;
  43. }
  44. }

4、编写DAO接口 DepartmentDao.java

  1. /**
  2. * 因为需要使用分页和条件查询,所以从JpaRepository接口 和 JpaSpecificationExecutor接口继承
  3. */
  4. public interface DepartmentDao extends JpaRepository<Department, Integer>, JpaSpecificationExecutor<Department> {
  5.  
  6. }

5、编写工具类 TreeNode.java 和  TreeUtil.java

  1. /**
  2. * EasyUI Tree的封装类
  3. */
  4. public class TreeNode {
  5. private Integer id; // 节点的 id
  6. private Integer parentId; // 父节点id,java生成树时使用
  7. private String text; // 显示的节点文字。
  8. private String iconCls; // 节点图标样式 "iconCls":"icon-save", "iconCls":"icon-ok", 等
  9. private String state; // 节点状态, 'open' 或 'closed',默认是 'open'。当设为 'closed' 时,此节点有子节点,并且将从远程站点加载它们。
  10. private String flag; // 节点类型
  11. private Integer trueId; // 应用系统真实 id
  12. private boolean checked; // 指示节点是否被选中。
  13. private LinkedHashMap<?, ?> attributes; // 给一个节点追加的自定义属性。
  14. private List<TreeNode> children; // 定义了一些子节点的节点数组。
  15. private String url; // 扩展属性url
  16.  
  17. public Integer getTrueId() {
  18. return trueId;
  19. }
  20.  
  21. public void setTrueId(Integer trueId) {
  22. this.trueId = trueId;
  23. }
  24.  
  25. public String getFlag() {
  26. return flag;
  27. }
  28.  
  29. public void setFlag(String flag) {
  30. this.flag = flag;
  31. }
  32.  
  33. public Integer getId() {
  34. return id;
  35. }
  36.  
  37. public void setId(Integer id) {
  38. this.id = id;
  39. }
  40.  
  41. public Integer getParentId() {
  42. return parentId;
  43. }
  44.  
  45. public void setParentId(Integer parentId) {
  46. this.parentId = parentId;
  47. }
  48.  
  49. public String getText() {
  50. return text;
  51. }
  52.  
  53. public void setText(String text) {
  54. this.text = text;
  55. }
  56.  
  57. public String getIconCls() {
  58. return iconCls;
  59. }
  60.  
  61. public void setIconCls(String iconCls) {
  62. this.iconCls = iconCls;
  63. }
  64.  
  65. public String getState() {
  66. return state;
  67. }
  68.  
  69. public void setState(String state) {
  70. this.state = state;
  71. }
  72.  
  73. public boolean isChecked() {
  74. return checked;
  75. }
  76.  
  77. public void setChecked(boolean checked) {
  78. this.checked = checked;
  79. }
  80.  
  81. public LinkedHashMap<?, ?> getAttributes() {
  82. return attributes;
  83. }
  84.  
  85. public void setAttributes(LinkedHashMap<?, ?> attributes) {
  86. this.attributes = attributes;
  87. }
  88.  
  89. public List<TreeNode> getChildren() {
  90. return children;
  91. }
  92.  
  93. public void setChildren(List<TreeNode> children) {
  94. this.children = children;
  95. }
  96.  
  97. public String getUrl() {
  98. return url;
  99. }
  100.  
  101. public void setUrl(String url) {
  102. this.url = url;
  103. }
  104. }
  1. /**
  2. * 树工具类
  3. */
  4. public class TreeUtil {
  5. /**
  6. * Tree装配方法
  7. *
  8. * @param tempTreeNodes
  9. * @param treeNodes
  10. * @return
  11. */
  12. public static List<TreeNode> Assemble(List<TreeNode> tempTreeNodes, List<TreeNode> treeNodes) {
  13. if (tempTreeNodes != null) {
  14. Map<Integer, TreeNode> map = new LinkedHashMap<>();
  15. for (TreeNode tn : tempTreeNodes) {
  16. map.put(tn.getId(), tn);
  17. }
  18.  
  19. TreeNode treeNode;
  20. TreeNode pTreeNode;
  21. for (Integer id : map.keySet()) {
  22. treeNode = map.get(id);
  23. if (treeNode.getParentId() == 0) {
  24. treeNodes.add(treeNode);
  25. } else {
  26. pTreeNode = map.get(treeNode.getParentId());
  27. List<TreeNode> children = pTreeNode.getChildren();
  28. if (children != null) {
  29. children.add(treeNode);
  30. } else {
  31. children = new ArrayList();
  32. children.add(treeNode);
  33. pTreeNode.setChildren(children);
  34. }
  35. }
  36. }
  37. }
  38.  
  39. return treeNodes;
  40. }
  41. }

6、规划控制器 DepartmentController.java

  1. @Controller
  2. @RequestMapping("/department")
  3. public class DepartmentController {
  4. @Autowired
  5. private DepartmentDao departmentDao;
  6.  
  7. @RequestMapping("/view")
  8. public String view() {
  9. // 跳转至【资源管理】页面
  10. return "department";
  11. }
  12.  
  13. @RequestMapping("/tree")
  14. @ResponseBody
  15. public String tree() {
  16. List<Department> list = departmentDao.findAll();
  17. List<TreeNode> tempTreeNodes = new ArrayList();
  18. List<TreeNode> treeNodes = new ArrayList();
  19.  
  20. // 组装Easyui的Tree必须要有id、parentId、text属性,转换之
  21. for (Department department : list) {
  22. TreeNode tempTreeNode = new TreeNode();
  23. tempTreeNode.setId(department.getDepartmentid());
  24. tempTreeNode.setParentId(department.getDepartmentpid());
  25. tempTreeNode.setText(department.getDepartmentname());
  26. tempTreeNodes.add(tempTreeNode);
  27. }
  28.  
  29. return JSONObject.toJSON(TreeUtil.Assemble(tempTreeNodes, treeNodes)).toString();
  30. }
  31.  
  32. @RequestMapping("/saveNode")
  33. @ResponseBody
  34. public Map<String, Object> saveNode(Integer departmentpid, String departmentname) {
  35. Department model = new Department();
  36. model.setDepartmentpid(departmentpid);
  37. model.setDepartmentname(departmentname);
  38.  
  39. Map<String, Object> resultMap = new HashMap<>();
  40. departmentDao.save(model);
  41. resultMap.put("success", true);
  42. return resultMap;
  43. }
  44.  
  45. @RequestMapping("/updateNode")
  46. @ResponseBody
  47. public Map<String, Object> updateNode(Department model) {
  48. Map<String, Object> resultMap = new HashMap<>();
  49. departmentDao.save(model);
  50. resultMap.put("success", true);
  51. return resultMap;
  52. }
  53.  
  54. @RequestMapping("/deleteNode")
  55. @ResponseBody
  56. public Map<String, Object> deleteNode(Integer departmentid) {
  57. Map<String, Object> resultMap = new HashMap<>();
  58. departmentDao.deleteById(departmentid);
  59. resultMap.put("success", true);
  60. return resultMap;
  61. }
  62. }

7、编写前端代码

HTML页面:department.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>测试Tree功能</title>
  6. <link rel="stylesheet" type="text/css" href="../easyui/themes/default/easyui.css">
  7. <link rel="stylesheet" type="text/css" href="../easyui/themes/icon.css">
  8. <script type="text/javascript" src="../easyui/jquery.min.js"></script>
  9. <script type="text/javascript" src="../easyui/jquery.easyui.min.js"></script>
  10. <script type="text/javascript" src="../easyui/locale/easyui-lang-zh_CN.js"></script>
  11. <script type="text/javascript" src="../biz/department.js"></script>
  12. </head>
  13. <body>
  14. <!-- 部门树 -->
  15. <ul id="deptTree" class="easyui-tree"></ul>
  16. <!-- 叶子节点右键菜单 -->
  17. <div id="leaf" class="easyui-menu" style="width: 120px;">
  18. <div onclick="addNode()" iconcls="icon-add">新增节点</div>
  19. <div onclick="removeNode()" iconcls="icon-remove">删除节点</div>
  20. <div onclick="updateNode()" iconcls="icon-edit">编辑节点</div>
  21. </div>
  22. <!-- 非叶子节点右键菜单 -->
  23. <div id="parentNode" class="easyui-menu" style="width: 120px;">
  24. <div onclick="addNode()" iconcls="icon-add">新增节点</div>
  25. <div onclick="updateNode()" iconcls="icon-edit">编辑节点</div>
  26. </div>
  27. <!-- 节点内容对话框 -->
  28. <div id="info" class="easyui-dialog" style="width:300px; height: 120px;" closed=true>
  29. <form id="treefrm" method="post">
  30. <input type="hidden" name="departmentid">
  31. <table style="margin: auto;" cellspacing="10">
  32. <tr>
  33. <td>部门名称</td>
  34. <td><input class="easyui-textbox" name="departmentname" value="" data-options="required:true"></td>
  35. </tr>
  36. </table>
  37. <div style="text-align: center; bottom: 15px; margin-top: 10px;">
  38. <a id="btnSave" class="easyui-linkbutton"
  39. data-options="iconCls:'icon-save'">保存</a>
  40. <a id="btnCancel" class="easyui-linkbutton"
  41. data-options="iconCls:'icon-cancel'">取消</a>
  42. </div>
  43. </form>
  44. </div>
  45. </body>
  46. </html>

对应JS文件:department.js

  1. // 记录添加还是修改
  2. var flag;
  3. // 临时存储选中节点数据
  4. var tempNode;
  5.  
  6. // 页面加载
  7. $(function () {
  8. // 菜单树绑定数据
  9. $('#deptTree').tree({
  10. url: '/department/tree',
  11. animate: true,
  12. lines: true,
  13. onBeforeSelect: function (node) {
  14. // onBeforeSelect事件:节点被选中前触发,返回false则取消选择动作
  15. if (!$(this).tree('isLeaf', node.target)) {
  16. // 不是叶子节点,则不能选中
  17. return false;
  18. }
  19. },
  20. onClick: function (node) {
  21. // alert(node.target.innerText);
  22. },
  23. onContextMenu: function (e, node) {
  24. // 记录选中的节点,为后续增删改操作提供节点数据
  25. tempNode = node;
  26.  
  27. // 阻止右键默认事件
  28. e.preventDefault();
  29.  
  30. // 判断该结点有没有父结点
  31. var root = $(this).tree('getParent', node.target);
  32. // 没有父节点则为根结点,可以新增、编辑,不可以删除
  33. if (root == null) {
  34. // 如果是根节点,则可以新增、编辑,不可以删除
  35. $('#parentNode').menu('show', {
  36. left: e.pageX,
  37. top: e.pageY
  38. });
  39. }
  40.  
  41. if ($(this).tree('isLeaf', node.target)) {
  42. // 如果是叶子节点,则可以新增、编辑和删除
  43. $('#leaf').menu('show', {
  44. left: e.pageX,
  45. top: e.pageY
  46. });
  47. } else {
  48. // 如果不是叶子节点,则可以新增、编辑,不可以删除
  49. $('#parentNode').menu('show', {
  50. left: e.pageX,
  51. top: e.pageY
  52. });
  53. }
  54. }
  55. });
  56.  
  57. // 保存按钮押下处理
  58. $('#btnSave').click(function () {
  59. var tempdata, tempurl, tempmsg;
  60.  
  61. if (flag == 'add') {
  62. tempurl = 'saveNode';
  63. tempmsg = '添加成功!';
  64. tempdata = {
  65. departmentpid: tempNode.id,
  66. departmentname: $('#treefrm').find('input[name=departmentname]').val()
  67. };
  68. } else if (flag == 'edit') {
  69. tempurl = 'updateNode';
  70. tempmsg = '编辑成功!';
  71. tempdata = {
  72. departmentid: $('#treefrm').find('input[name=departmentid]').val(),
  73. departmentpid: $('#deptTree').tree('getParent', tempNode.target).id,
  74. departmentname: $('#treefrm').find('input[name=departmentname]').val()
  75. };
  76. }
  77.  
  78. $.ajax({
  79. type: 'post',
  80. async: true,
  81. url: tempurl,
  82. data: tempdata,
  83. dataType: 'json',
  84. success: function (result) {
  85. // 树重新加载
  86. $('#deptTree').tree('reload');
  87.  
  88. $.messager.show({
  89. title: '提示信息',
  90. msg: tempmsg
  91. });
  92. },
  93. error: function (result) {
  94. // 请求失败时执行该函数
  95. $.messager.show({
  96. title: '错误信息',
  97. msg: result.msg
  98. });
  99. }
  100. });
  101.  
  102. $('#treefrm').form('clear');
  103. $('#info').dialog('close');
  104. });
  105.  
  106. // 取消按钮押下处理
  107. $('#btnCancel').click(function () {
  108. $('#treefrm').form('clear');
  109. $('#info').dialog('close');
  110. });
  111. });
  112.  
  113. // 新增节点
  114. var addNode = function () {
  115. flag = 'add';
  116. // 清空表单数据
  117. $('#treefrm').form('clear');
  118. // 打开dialog
  119. $('#info').dialog('open').dialog('setTitle', '新增');
  120. };
  121.  
  122. // 编辑节点
  123. var updateNode = function () {
  124. flag = 'edit';
  125. // 清空表单数据
  126. $('#treefrm').form('clear');
  127. $('#treefrm').form('load', {
  128. departmentid: tempNode.id,
  129. departmentname: tempNode.text
  130. });
  131. // 打开dialog
  132. $('#info').dialog('open').dialog('setTitle', '编辑');
  133. };
  134.  
  135. // 删除节点
  136. var removeNode = function () {
  137. // 前台删除
  138. $('#deptTree').tree('remove', tempNode.target);
  139.  
  140. // 后台删除
  141. $.ajax({
  142. type: "post",
  143. async: true, // 异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行)
  144. url: "deleteNode",
  145. data: {departmentid: tempNode.id},
  146. dataType: "json", // 返回数据形式为json
  147. success: function (result) {
  148. // 请求成功时执行该函数内容,result即为服务器返回的json对象
  149. $.messager.show({
  150. title: '提示信息',
  151. msg: '删除成功!'
  152. });
  153. },
  154. error: function (result) {
  155. // 请求失败时执行该函数
  156. $.messager.show({
  157. title: '错误信息',
  158. msg: result.msg
  159. });
  160. }
  161. });
  162. };

8、运行效果

【原】无脑操作:EasyUI Tree实现左键只选择叶子节点、右键浮动菜单实现增删改的更多相关文章

  1. EasyUI Combotree只选择叶子节点

    EasyUI Combotree的方法拓展自Combo和Tree.而Tree有一个onBeforSelect事件来帮助我们实现只选择叶子节点的功能. Tree事件需要 'node' 参数,它包括下列属 ...

  2. 【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础授权权限

    上一篇<[原]无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限>介绍了实现Shiro的基础认证.本篇谈谈实现 ...

  3. 【原】无脑操作:IDEA + maven + Shiro + SpringBoot + JPA + Thymeleaf实现基础认证权限

    开发环境搭建参见<[原]无脑操作:IDEA + maven + SpringBoot + JPA + Thymeleaf实现CRUD及分页> 需求: ① 除了登录页面,在地址栏直接访问其他 ...

  4. 【原】无脑操作:express + MySQL 实现CRUD

    基于node.js的web开发框架express简单方便,很多项目中都在使用.这里结合MySQL数据库,实现最简单的CRUD操作. 开发环境: IDE:WebStorm DB:MySQL ------ ...

  5. Jquery EasyUI Combotree只能选择叶子节点且叶子节点有多选框

    Jquery EasyUI Combotree只能选择叶子节点且叶子节点有多选框 Jquery EasyUI Combotree单选框,Jquery EasyUI Combotree只能选择叶子节点 ...

  6. 【原】无脑操作:eclipse + maven搭建SSM框架

    网上看到一些Spring + Spring MVC + MyBatis框架的搭建教程,不是很详细或是时间久远了,自己动手整一个简单无脑的! 0.系统环境 1)Windows 10 企业版 2)JDK ...

  7. 【原】无脑操作:ElasticSearch学习笔记(01)

    开篇来自于经典的“保安的哲学三问”(你是谁,在哪儿,要干嘛) 问题一.ElasticSearch是什么?有什么用处? 答:截至2018年12月28日,从ElasticSearch官网(https:// ...

  8. easyui Tree模拟级联勾选cascadeCheck,节点选择,父节点自动选中,节点取消,父节点自动取消选择,节点选择,所有子节点全部选择,节点取消,所有子节点全部取消勾选

    最近项目中用到easyui tree,发现tree控件的cascadeCheck有些坑,不像miniui 的tree控件,级联勾选符合业务需求,所以就自己重新改写了onCheck事件,符合业务需求.网 ...

  9. EasyUI Combotree 只允许选择 叶子节点

    $("#SDID").combotree({ url: '/Ajax/GetDeptTree.aspx?level=4&pid=-1', onSelect: functio ...

随机推荐

  1. windows无人值守文件的制作_autounattend.xml

    网址:http://www.windowsafg.com/office2010.html  Note:网络不能是国内网络(需要FQ),否则不能生成自动应答文件. 以Windows10为例:Window ...

  2. 积极参与开源项目,促进.NET Core生态社区发展

    今天早上在微信群里聊天聊到百度的SDK 已经支持.NET Core, 百度已经在3月份就支持了,想起当时还是我在他们的github上提的issue: https://github.com/Baidu- ...

  3. 以Windows服务方式运行.NET Core程序

    在之前一篇博客<以Windows服务方式运行ASP.NET Core程序>中我讲述了如何把ASP.NET Core程序作为Windows服务运行的方法,而今,我们又遇到了新的问题,那就是: ...

  4. javascript 字符串转换数字的方法大总结

    方法主要有三种 转换函数.强制类型转换.利用js变量弱类型转换. 1. 转换函数: js提供了parseInt()和parseFloat()两个转换函数.前者把值转换成整数,后者把值转换成浮点数.只有 ...

  5. 【安富莱STM32H7教程】第1章 初学STM32H7的准备工作

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第1章   初学STM32H7的准备工作 俗话说万事开头 ...

  6. MySQL中的自适应哈希索引

    众所周知,InnoDB使用的索引结构是B+树,但其实它还支持另一种索引:自适应哈希索引. 哈希表是数组+链表的形式.通过哈希函数计算每个节点数据中键所对应的哈希桶位置,如果出现哈希冲突,就使用拉链法来 ...

  7. python安装第三方库报错visual c++ 14.0 is required

    使用python安装第三方库时报错如下: error: Microsoft Visual C++ 14.0 is required. Get it with “Microsoft Visual C++ ...

  8. 7.Flask文件上传

     1.1.上传文件和访问上传的文件 upload_file_demo.py from flask import Flask,request,render_template import os from ...

  9. 【Android Studio安装部署系列】二十五、Android studio使用NDK生成so文件和arr文件

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 Android Studio使用ndk的简单步骤. NDK环境搭建 下载NDK 下载链接:https://developer.and ...

  10. .net core自定义高性能的Web API服务网关

    网关对于服务起到一个统一控制处理的作用,也便于客户端更好的调用:通过网关可以灵活地控制服务应用接口负载,故障迁移,安全控制,监控跟踪和日志处理等.由于网关在性能和可靠性上都要求非常严格,所以针对业务需 ...