【原】無腦操作:EasyUI Tree實現左鍵只選擇葉子節點、右鍵浮動菜單實現增刪改


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、運行效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM