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

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

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

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

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

实现方法如下:

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

2、建库建表

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

3、创建实体类 Department.java

 @Entity
@Table(name = "biz_department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "departmentid")
private Integer departmentid;
@Column(name = "departmentpid")
private Integer departmentpid;
@Column(name = "departmentname")
private String departmentname; public Department() {
} public Department(Integer departmentpid, String departmentname) {
this.departmentpid = departmentpid;
this.departmentname = departmentname;
} public Integer getDepartmentid() {
return departmentid;
} public void setDepartmentid(Integer departmentid) {
this.departmentid = departmentid;
} public Integer getDepartmentpid() {
return departmentpid;
} public void setDepartmentpid(Integer departmentpid) {
this.departmentpid = departmentpid;
} public String getDepartmentname() {
return departmentname;
} public void setDepartmentname(String departmentname) {
this.departmentname = departmentname;
}
}

4、编写DAO接口 DepartmentDao.java

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

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

 /**
* EasyUI Tree的封装类
*/
public class TreeNode {
private Integer id; // 节点的 id
private Integer parentId; // 父节点id,java生成树时使用
private String text; // 显示的节点文字。
private String iconCls; // 节点图标样式 "iconCls":"icon-save", "iconCls":"icon-ok", 等
private String state; // 节点状态, 'open' 或 'closed',默认是 'open'。当设为 'closed' 时,此节点有子节点,并且将从远程站点加载它们。
private String flag; // 节点类型
private Integer trueId; // 应用系统真实 id
private boolean checked; // 指示节点是否被选中。
private LinkedHashMap<?, ?> attributes; // 给一个节点追加的自定义属性。
private List<TreeNode> children; // 定义了一些子节点的节点数组。
private String url; // 扩展属性url public Integer getTrueId() {
return trueId;
} public void setTrueId(Integer trueId) {
this.trueId = trueId;
} public String getFlag() {
return flag;
} public void setFlag(String flag) {
this.flag = flag;
} public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public Integer getParentId() {
return parentId;
} public void setParentId(Integer parentId) {
this.parentId = parentId;
} public String getText() {
return text;
} public void setText(String text) {
this.text = text;
} public String getIconCls() {
return iconCls;
} public void setIconCls(String iconCls) {
this.iconCls = iconCls;
} public String getState() {
return state;
} public void setState(String state) {
this.state = state;
} public boolean isChecked() {
return checked;
} public void setChecked(boolean checked) {
this.checked = checked;
} public LinkedHashMap<?, ?> getAttributes() {
return attributes;
} public void setAttributes(LinkedHashMap<?, ?> attributes) {
this.attributes = attributes;
} public List<TreeNode> getChildren() {
return children;
} public void setChildren(List<TreeNode> children) {
this.children = children;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
}
}
 /**
* 树工具类
*/
public class TreeUtil {
/**
* Tree装配方法
*
* @param tempTreeNodes
* @param treeNodes
* @return
*/
public static List<TreeNode> Assemble(List<TreeNode> tempTreeNodes, List<TreeNode> treeNodes) {
if (tempTreeNodes != null) {
Map<Integer, TreeNode> map = new LinkedHashMap<>();
for (TreeNode tn : tempTreeNodes) {
map.put(tn.getId(), tn);
} TreeNode treeNode;
TreeNode pTreeNode;
for (Integer id : map.keySet()) {
treeNode = map.get(id);
if (treeNode.getParentId() == 0) {
treeNodes.add(treeNode);
} else {
pTreeNode = map.get(treeNode.getParentId());
List<TreeNode> children = pTreeNode.getChildren();
if (children != null) {
children.add(treeNode);
} else {
children = new ArrayList();
children.add(treeNode);
pTreeNode.setChildren(children);
}
}
}
} return treeNodes;
}
}

6、规划控制器 DepartmentController.java

 @Controller
@RequestMapping("/department")
public class DepartmentController {
@Autowired
private DepartmentDao departmentDao; @RequestMapping("/view")
public String view() {
// 跳转至【资源管理】页面
return "department";
} @RequestMapping("/tree")
@ResponseBody
public String tree() {
List<Department> list = departmentDao.findAll();
List<TreeNode> tempTreeNodes = new ArrayList();
List<TreeNode> treeNodes = new ArrayList(); // 组装Easyui的Tree必须要有id、parentId、text属性,转换之
for (Department department : list) {
TreeNode tempTreeNode = new TreeNode();
tempTreeNode.setId(department.getDepartmentid());
tempTreeNode.setParentId(department.getDepartmentpid());
tempTreeNode.setText(department.getDepartmentname());
tempTreeNodes.add(tempTreeNode);
} return JSONObject.toJSON(TreeUtil.Assemble(tempTreeNodes, treeNodes)).toString();
} @RequestMapping("/saveNode")
@ResponseBody
public Map<String, Object> saveNode(Integer departmentpid, String departmentname) {
Department model = new Department();
model.setDepartmentpid(departmentpid);
model.setDepartmentname(departmentname); Map<String, Object> resultMap = new HashMap<>();
departmentDao.save(model);
resultMap.put("success", true);
return resultMap;
} @RequestMapping("/updateNode")
@ResponseBody
public Map<String, Object> updateNode(Department model) {
Map<String, Object> resultMap = new HashMap<>();
departmentDao.save(model);
resultMap.put("success", true);
return resultMap;
} @RequestMapping("/deleteNode")
@ResponseBody
public Map<String, Object> deleteNode(Integer departmentid) {
Map<String, Object> resultMap = new HashMap<>();
departmentDao.deleteById(departmentid);
resultMap.put("success", true);
return resultMap;
}
}

7、编写前端代码

HTML页面:department.html

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试Tree功能</title>
<link rel="stylesheet" type="text/css" href="../easyui/themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="../easyui/themes/icon.css">
<script type="text/javascript" src="../easyui/jquery.min.js"></script>
<script type="text/javascript" src="../easyui/jquery.easyui.min.js"></script>
<script type="text/javascript" src="../easyui/locale/easyui-lang-zh_CN.js"></script>
<script type="text/javascript" src="../biz/department.js"></script>
</head>
<body>
<!-- 部门树 -->
<ul id="deptTree" class="easyui-tree"></ul>
<!-- 叶子节点右键菜单 -->
<div id="leaf" class="easyui-menu" style="width: 120px;">
<div onclick="addNode()" iconcls="icon-add">新增节点</div>
<div onclick="removeNode()" iconcls="icon-remove">删除节点</div>
<div onclick="updateNode()" iconcls="icon-edit">编辑节点</div>
</div>
<!-- 非叶子节点右键菜单 -->
<div id="parentNode" class="easyui-menu" style="width: 120px;">
<div onclick="addNode()" iconcls="icon-add">新增节点</div>
<div onclick="updateNode()" iconcls="icon-edit">编辑节点</div>
</div>
<!-- 节点内容对话框 -->
<div id="info" class="easyui-dialog" style="width:300px; height: 120px;" closed=true>
<form id="treefrm" method="post">
<input type="hidden" name="departmentid">
<table style="margin: auto;" cellspacing="10">
<tr>
<td>部门名称</td>
<td><input class="easyui-textbox" name="departmentname" value="" data-options="required:true"></td>
</tr>
</table>
<div style="text-align: center; bottom: 15px; margin-top: 10px;">
<a id="btnSave" class="easyui-linkbutton"
data-options="iconCls:'icon-save'">保存</a>
<a id="btnCancel" class="easyui-linkbutton"
data-options="iconCls:'icon-cancel'">取消</a>
</div>
</form>
</div>
</body>
</html>

对应JS文件:department.js

 // 记录添加还是修改
var flag;
// 临时存储选中节点数据
var tempNode; // 页面加载
$(function () {
// 菜单树绑定数据
$('#deptTree').tree({
url: '/department/tree',
animate: true,
lines: true,
onBeforeSelect: function (node) {
// onBeforeSelect事件:节点被选中前触发,返回false则取消选择动作
if (!$(this).tree('isLeaf', node.target)) {
// 不是叶子节点,则不能选中
return false;
}
},
onClick: function (node) {
// alert(node.target.innerText);
},
onContextMenu: function (e, node) {
// 记录选中的节点,为后续增删改操作提供节点数据
tempNode = node; // 阻止右键默认事件
e.preventDefault(); // 判断该结点有没有父结点
var root = $(this).tree('getParent', node.target);
// 没有父节点则为根结点,可以新增、编辑,不可以删除
if (root == null) {
// 如果是根节点,则可以新增、编辑,不可以删除
$('#parentNode').menu('show', {
left: e.pageX,
top: e.pageY
});
} if ($(this).tree('isLeaf', node.target)) {
// 如果是叶子节点,则可以新增、编辑和删除
$('#leaf').menu('show', {
left: e.pageX,
top: e.pageY
});
} else {
// 如果不是叶子节点,则可以新增、编辑,不可以删除
$('#parentNode').menu('show', {
left: e.pageX,
top: e.pageY
});
}
}
}); // 保存按钮押下处理
$('#btnSave').click(function () {
var tempdata, tempurl, tempmsg; if (flag == 'add') {
tempurl = 'saveNode';
tempmsg = '添加成功!';
tempdata = {
departmentpid: tempNode.id,
departmentname: $('#treefrm').find('input[name=departmentname]').val()
};
} else if (flag == 'edit') {
tempurl = 'updateNode';
tempmsg = '编辑成功!';
tempdata = {
departmentid: $('#treefrm').find('input[name=departmentid]').val(),
departmentpid: $('#deptTree').tree('getParent', tempNode.target).id,
departmentname: $('#treefrm').find('input[name=departmentname]').val()
};
} $.ajax({
type: 'post',
async: true,
url: tempurl,
data: tempdata,
dataType: 'json',
success: function (result) {
// 树重新加载
$('#deptTree').tree('reload'); $.messager.show({
title: '提示信息',
msg: tempmsg
});
},
error: function (result) {
// 请求失败时执行该函数
$.messager.show({
title: '错误信息',
msg: result.msg
});
}
}); $('#treefrm').form('clear');
$('#info').dialog('close');
}); // 取消按钮押下处理
$('#btnCancel').click(function () {
$('#treefrm').form('clear');
$('#info').dialog('close');
});
}); // 新增节点
var addNode = function () {
flag = 'add';
// 清空表单数据
$('#treefrm').form('clear');
// 打开dialog
$('#info').dialog('open').dialog('setTitle', '新增');
}; // 编辑节点
var updateNode = function () {
flag = 'edit';
// 清空表单数据
$('#treefrm').form('clear');
$('#treefrm').form('load', {
departmentid: tempNode.id,
departmentname: tempNode.text
});
// 打开dialog
$('#info').dialog('open').dialog('setTitle', '编辑');
}; // 删除节点
var removeNode = function () {
// 前台删除
$('#deptTree').tree('remove', tempNode.target); // 后台删除
$.ajax({
type: "post",
async: true, // 异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行)
url: "deleteNode",
data: {departmentid: tempNode.id},
dataType: "json", // 返回数据形式为json
success: function (result) {
// 请求成功时执行该函数内容,result即为服务器返回的json对象
$.messager.show({
title: '提示信息',
msg: '删除成功!'
});
},
error: function (result) {
// 请求失败时执行该函数
$.messager.show({
title: '错误信息',
msg: result.msg
});
}
});
};

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. Linux记录~持续更新~

    ls -ildha /etc -i 显示对应id号 唯一标识 -l 显示详情 -d 显示当前文件夹 不包括子目录 -h 单位为KB 而不是B -a 显示所有 包括隐藏文件 mkdir mkdir -p ...

  2. 使用async await 封装 axios

    异步变同步: 厉害-- https://www.jianshu.com/p/4168efdc172b

  3. Linux内存管理 (5)slab分配器

    专题:Linux内存管理专题 关键词:slab/slub/slob.slab描述符.kmalloc.本地/共享对象缓冲池.slabs_partial/slabs_full/slabs_free.ava ...

  4. 百度APP移动端网络深度优化实践分享(二):网络连接优化篇

    本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为<百度App网络深度优化系列<二>连接优化>,感谢原作者的无私分享. 一.前言 在<百度APP移动端网 ...

  5. SQL中关于不能显示count为0的行的问题

    今天在写自己一个博客项目时遇到了一个数据库问题,因为对于数据库自己所知道的还是很浅显的,对一些查询语句不怎么熟悉. 我目前有一个文章表和评论表,评论表里面有个post_id对应文章表里面的id,想查询 ...

  6. 内核ring buffer -- kfifo

    目前kernel的kfifo根据版本有两种形式, 早期的函数形式和现在的宏定义形式 1. 早期的(linux-3.0.56/kernel/kfifo.c) 感兴趣读者可以自己看, 源码如下: /* * ...

  7. PHP内核之旅-5.强大的数组

    PHP 内核之旅系列 PHP内核之旅-1.生命周期 PHP内核之旅-2.SAPI中的Cli PHP内核之旅-3.变量 PHP内核之旅-4.字符串 PHP内核之旅-5.强大的数组 PHP内核之旅-6.垃 ...

  8. springboot的war和jar包

    本篇和大家分享的是通过maven对springboot中打war包和jar包:war通常来说生成后直接放到tomcat的webapps下面就行,tomcat配置自动解压war,而jar一般通过命令行部 ...

  9. PERL学习笔记---正则表达式的应用

    使用m//匹配 //这是m//(模式匹配)的一种简写.同qw//操作一样,可以使用任何成对的分隔符.因此,可以使用m(fred), m<fred>, m{fred}, m[fred],或者 ...

  10. Python基础(解压序列)

    解压序列: a,b=(1,2) # a,b=[1,2] print(a,b) #输出结果:1 2 #获取第一个值和最后一个值 a,*_,c=(1,2,3,4,5,6,7,8,9) print(a) p ...