在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
}