在web开发中,树是比较常见的东西。以前用过zTree,也用过EasyUI-Tree,过了好久后发现都忘记怎么用了。
这几天重新回顾了EasyUI-tree的使用,在此将相关知识点记录下来。
一、EasyUI-Tree的官方介绍
(1)基本使用的介绍
使用方式:

数据格式:

更多详细知识见官方文档:
(2)异步树的使用
一般情况下,异步树使用得比较多。异步树就是指当你点击展开某个树的节点时,该节点才向后台发请求去加载子节点。
关键点:
异步树的数据结构中,每个节点必须包含id、text、state这3个属性。而且,如果该个节点有子节点(即他是父节点),
那么他的state必须是closed的,这样在该节点默认就是闭合的;在展开他的时候才会向后台发请求,
把他的id带过去查他的子节点。
看看官方的异步树的案例:



看完上面这3张官方介绍的截图,大概就懂了异步树是怎么玩的了。下面来分析下后台代码吧。
笔者不懂php,不过也可以来分析下
- 首先,载入含有树组件的页面时,会向后台发请求,请求url就是tree的url;此时是没传id过来的
- 如果没带id过来,那么把id默认设为0,然后去后台查询父id等于id的数据
- 如果带了id就直接查询父id等于id的数据
- 查询出数据来后,对数据进行封装;必须包含id,text,state属性。而且state属性是根据有没有子节点来赋值
- 将数据封装好后,返回json数据。
二、开发实战-前台
先看下笔者开发好的效果,感觉差强人意。

js代码:
<script type="text/javascript">
$(function(){
// 从远程加载树的数据
$('#tt').tree({
url:'${basePath}nsfw/tree_findByPId.action',
lines:true
});
});//end of window onload
</script>
10
1
<script type="text/javascript">
2
$(function(){
3
// 从远程加载树的数据
4
$('#tt').tree({
5
url:'${basePath}nsfw/tree_findByPId.action',
6
lines:true
7
});
8
9
});//end of window onload
10
</script>
jsp代码:
<body>
<!-- 树容器 -->
<ul id="tt"></ul>
</body>
4
1
<body>
2
<!-- 树容器 -->
3
<ul id="tt"></ul>
4
</body>
三、开发实战-后台
后台代码相对简单,就只需要查询出带过来的id的子节点就可以。
(1)实体类代码
package com.tax.pojo.nsfw;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* OrgTree(用于测试EasyUI的Tree)
* @author ZENG.XIAO.YAN
* @date 2017年8月24日 上午9:24:54
* @version v1.0
*/
@Entity
@Table(name="org_tree")
public class OrgTree implements Serializable {
/** serialVersionUID */
private static final long serialVersionUID = 6661807356404913246L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column
private Integer id;
@Column
private String title;
@Column(name="p_id")
private Integer pId;
@Column(name="is_parent")
private boolean isParent;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean getIsParent() {
return isParent;
}
public void setIsParent(boolean isParent) {
this.isParent = isParent;
}
public Integer getpId() {
return pId;
}
public void setpId(Integer pId) {
this.pId = pId;
}
// 这个2个get方法主要用于tree的数据,tree数据需要 {"id":1,"text":"root","state":"closed"}
public String getText() {
return getTitle();
}
public String getState() {
return getIsParent() ? "closed" : "open";
}
}
x
1
package com.tax.pojo.nsfw;
2
3
import java.io.Serializable;
4
import javax.persistence.Column;
5
import javax.persistence.Entity;
6
import javax.persistence.GeneratedValue;
7
import javax.persistence.GenerationType;
8
import javax.persistence.Id;
9
import javax.persistence.Table;
10
11
/**
12
* OrgTree(用于测试EasyUI的Tree)
13
* @author ZENG.XIAO.YAN
14
* @date 2017年8月24日 上午9:24:54
15
* @version v1.0
16
*/
17
18
name="org_tree") (
19
public class OrgTree implements Serializable {
20
/** serialVersionUID */
21
private static final long serialVersionUID = 6661807356404913246L;
22
23
(strategy=GenerationType.IDENTITY)
24
25
private Integer id;
26
27
private String title;
28
(name="p_id")
29
private Integer pId;
30
(name="is_parent")
31
private boolean isParent;
32
33
public Integer getId() {
34
return id;
35
}
36
37
public void setId(Integer id) {
38
this.id = id;
39
}
40
41
public String getTitle() {
42
return title;
43
}
44
45
public void setTitle(String title) {
46
this.title = title;
47
}
48
49
public boolean getIsParent() {
50
return isParent;
51
}
52
53
public void setIsParent(boolean isParent) {
54
this.isParent = isParent;
55
}
56
57
public Integer getpId() {
58
return pId;
59
}
60
61
public void setpId(Integer pId) {
62
this.pId = pId;
63
}
64
65
// 这个2个get方法主要用于tree的数据,tree数据需要 {"id":1,"text":"root","state":"closed"}
66
public String getText() {
67
return getTitle();
68
}
69
public String getState() {
70
return getIsParent() ? "closed" : "open";
71
}
72
73
}
(2)Action代码
注意一点:根节点必须要自己手动在数据库插入数据,它的父id必须为0,且它是必须是父节点。
/** 通过树父节点id查找子节点 */
public String findByPId() {
if(id == null){
id = 0;
}
// 通过传来的父id查询出数据
List<OrgTree> list = orgTreeService.findListByPId(id);
// 封装数据
responseData = list; //这里用了struts2的json插件,且配置了root为responseData
return SUCCESS;
}
11
1
/** 通过树父节点id查找子节点 */
2
public String findByPId() {
3
if(id == null){
4
id = 0;
5
}
6
// 通过传来的父id查询出数据
7
List<OrgTree> list = orgTreeService.findListByPId(id);
8
// 封装数据
9
responseData = list; //这里用了struts2的json插件,且配置了root为responseData
10
return SUCCESS;
11
}
通过上面这段代码可以实现异步树。效果如下图

下面为题外话
ps:上面这样其实已经把功能实现了,但是,可能你的产品经理不喜欢加载页面进来就只能看到一个根节点。比如:他希望通过页面进来后,能看到根节点展开的效果;也就是把根节点的子节点显示出来。
解决这个问题不难,就是在加载根节点的时候,把子节点(不包含孙节点,只要子节点)内容也查出来,且把根节点的state设为open。
下面上代码:
/** 通过树父节点id查找子节点 */
public String findByPId() {
if(id == null){
id = 0;
}
// 通过传来的父id查询出数据
List<OrgTree> list = orgTreeService.findListByPId(id);
// 封装数据
/** 上面的父id为0的话,只会显示根节点,因此我们处理下,显示根节点和一级子节点 */
if(id == 0){
OrgTree rootTree = list.get(0);
// 我们下面就把根节点的子节点查出来,封装到children属性
List<OrgTree> childList = orgTreeService.findListByPId(rootTree.getId());
responseData = new ArrayList();
HashMap<String,Object> map = new HashMap<>();
map.put("id", rootTree.getId());
map.put("text", rootTree.getText());
map.put("state", "open");
map.put("children", childList);
responseData.add(map);
}else{
responseData = list;
}
return SUCCESS;
}
25
1
/** 通过树父节点id查找子节点 */
2
public String findByPId() {
3
if(id == null){
4
id = 0;
5
}
6
// 通过传来的父id查询出数据
7
List<OrgTree> list = orgTreeService.findListByPId(id);
8
// 封装数据
9
/** 上面的父id为0的话,只会显示根节点,因此我们处理下,显示根节点和一级子节点 */
10
if(id == 0){
11
OrgTree rootTree = list.get(0);
12
// 我们下面就把根节点的子节点查出来,封装到children属性
13
List<OrgTree> childList = orgTreeService.findListByPId(rootTree.getId());
14
responseData = new ArrayList();
15
HashMap<String,Object> map = new HashMap<>();
16
map.put("id", rootTree.getId());
17
map.put("text", rootTree.getText());
18
map.put("state", "open");
19
map.put("children", childList);
20
responseData.add(map);
21
}else{
22
responseData = list;
23
}
24
return SUCCESS;
25
}
效果:

四、开发实战-前台刷新tree的节点的处理
在新增、编辑、删除树的节点后都需要对树的节点刷新。比如在一个节点下面新增了节点,那么该节点肯定是要刷新的。
但是,笔者发现刷新的方法reload的第二个参数应该填是当前节点的父节点的dom对象。这点好奇怪,就像生了个孙子,要刷新爷爷的感觉。
经过笔者的验证,这样刷新是可行的。但当前节点是根节点时,就没父节点了,只能刷新自己了。
下面上一段js代码,就是刷新树的。传入参数可以是该节点对象,也可以是该节点的id
// 用于刷新节点,是window的方法,可跨freamset调用
function targetTreeReload(node){
// 如果node.target为undefined说明传的是id
if(node.target == undefined){
// 需要通过id找到节点(node此时是id),然后重新赋值给node
node = $('#tt').tree('find', node);
}
var parentNode = $("#tt").tree("getParent",node.target);
alert(parentNode);
// node.target表示该节点的DOM对象
if(parentNode == null){
// 为null代表当前节点已经是根节点了
$("#tt").tree("reload",node.target);
}else{
$("#tt").tree("reload",parentNode.target);
}
}
1
// 用于刷新节点,是window的方法,可跨freamset调用
2
function targetTreeReload(node){
3
// 如果node.target为undefined说明传的是id
4
if(node.target == undefined){
5
// 需要通过id找到节点(node此时是id),然后重新赋值给node
6
node = $('#tt').tree('find', node);
7
}
8
var parentNode = $("#tt").tree("getParent",node.target);
9
alert(parentNode);
10
// node.target表示该节点的DOM对象
11
if(parentNode == null){
12
// 为null代表当前节点已经是根节点了
13
$("#tt").tree("reload",node.target);
14
}else{
15
$("#tt").tree("reload",parentNode.target);
16
}
17
}