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

时间:2022-09-02 15:21:00

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实现左键只选择叶子节点、右键浮动菜单实现增删改【原】无脑操作:EasyUI Tree实现左键只选择叶子节点、右键浮动菜单实现增删改【原】无脑操作:EasyUI Tree实现左键只选择叶子节点、右键浮动菜单实现增删改【原】无脑操作:EasyUI Tree实现左键只选择叶子节点、右键浮动菜单实现增删改【原】无脑操作:EasyUI Tree实现左键只选择叶子节点、右键浮动菜单实现增删改

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

  1. EasyUI Combotree只选择叶子节点

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

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

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

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

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

  4. 【原】无脑操作:express &plus; 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 &plus; 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. Andriod环境搭建

    安卓是一款现在在移动端十分流行的系统,本人出于好奇心,希望彻底了解安卓的开发技. 首先了解一下安卓的系统构架,安卓大致分为四层架构,五块区域: 1.Linux内核层 Andriod是基于Linux2. ...

  2. 夺命雷公狗---DEDECMS----32dedecms电影网评价星星功能的实现

    我们要完成的是电影网的评价功能: 我们要做这个功能前,就要让前期工作准备好,首先让鼠标移动到星星时,星星的左边都是黄色的星星右边还是灰星星. 我们打开内容页的模版看下他代码是如何组成的: 我们在这里可 ...

  3. EasyUI 使用注意点

    前段时间做一个系统的服务端管理系统,使用了一下EasyUI.以下是我在使用中觉得需要注意的地方或者一些EasyUI中一些特别点的用法. 总结如下,与大家分享下,希望对初学者能有些作用. EasyUI ...

  4. VC&plus;&plus; 在两个文件互相包含时会出现的错误

    首先,要分别在两个文件中实现以下两个类 class Object { public: NewType ToType(); }; class NewType : public Object { } -- ...

  5. redis入门指南-第7章-管理

    7.1 持久化 1.RDB方式 2.AOF方式 Redis 持久化: 提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF. RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(poi ...

  6. centos7如何查询已运行服务?

    使用 systemctl list-unit-files 可以查看启动项 , 因为用chkconfig --list命令出现如下提示: 左边是服务名称,右边是状态,enabled是开机启动,disab ...

  7. Web jsp开发学习——前端后台传参方法

    一.前端传后台: 1.1表单数据的传递   前端的表单里定义名字name   后台通过名字获取输入的值         1.2页面点击了哪个按钮传递 登录注销的另一种方式   点击登录的地方设置参数 ...

  8. IntelliJ IDEA 注释模板设置

    1.idea类注释 打开:file->setting->Editor->Filr and Code Templates->Includes->File Header 类注 ...

  9. iis7 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理

    cmd 输入 C:\Windows\Microsoft.NET\Framework\V4.0.30319\aspnet_regiis -i

  10. 用Python写简单的爬虫

    准备: 1.扒网页,根据URL来获取网页信息 import urllib.parse import urllib.request response = urllib.request.urlopen(& ...