# 树形组件

树形组件 树形结构组件
Author zhangyun1@expservice.com.cn

# 示例

常规

配置参数

是否默认全部展开 是否复选 节点是否可拖拽
通过 node 设置 通过 node 获取 通过 key 设置
通过 key 获取 清空
常规
<template>
  <ht-row style="width:100%;padding:10px 20px;">
    <ht-col :span="12">
      <ht-input
        v-model="filterText"
        placeholder="输入关键字进行过滤"
        style="width:200px"
      />
      <!--
        node-key:设置tree节点的唯一key
        filter-node-method:设置过滤方法
        tree-data:设置tree的内容
        tree-props:设置tree的节点和label属性
        draggable:设置tree是否可拖拽
        show-checkbox:设置tree是否多选
        default-expand-all:设置默认是否全部展开
        node-click:点击树节点响应事件
      -->
      <ht-tree 
        ref="tree1"
        node-key="id"
        :filter-node-method="handleFilterNode" 
        :tree-data="treeData" 
        :tree-props="defaultProps" 
        :draggable="isDraggable" 
        :show-checkbox="showCheckbox" 
        :default-expand-all="isDefaultExpandAll" 
        @node-click="handleNodeClick" 
      />
    </ht-col>
    <ht-col :span="12">
      <div>
        <p>配置参数</p>
        <ht-checkbox v-model="isDefaultExpandAll">是否默认全部展开</ht-checkbox>
        <ht-checkbox v-model="showCheckbox">是否复选</ht-checkbox>
        <ht-checkbox v-model="isDraggable">节点是否可拖拽</ht-checkbox>
      </div>
      <div class="buttons">
        <ht-button @click="setCheckedNodes">通过 node 设置</ht-button>
        <ht-button @click="getCheckedNodes">通过 node 获取</ht-button>
        <ht-button @click="setCheckedKeys">通过  key  设置</ht-button>
      </div>
      <div class="buttons">
        <ht-button @click="getCheckedKeys">通过  key  获取</ht-button>
        <ht-button @click="resetChecked">清空</ht-button>
      </div>
    </ht-col>
  </ht-row>
</template>
<script>
export default {
  data() {
    return {
      filterText: '', // 树形过滤内容
      isDefaultExpandAll: true, // 默认是否全部展开
      showCheckbox: true, // 是否显示复选框
      isDraggable: false, // 节点是否可拖拽
      isLazy: true, // 是否懒加载
      treeData: [
        {
          id: 1,
          label: '一级 1',
          children: [{
            id: 2,
            label: '二级 1-1',
            children: [{
              id: 3,
              label: '三级 1-1-1'
            }]
          }]
        }, {
          id: 4,
          label: '一级 2',
          children: [{
            id: 5,
            label: '二级 2-1',
            children: [{
              id: 6,
              label: '三级 2-1-1'
            }]
          }, {
            id: 7,
            label: '二级 2-2',
            children: [{
              id: 8,
              label: '三级 2-2-1'
            }]
          }]
        }, {
          id: 9,
          label: '一级 3',
          children: [{
            id: 10,
            label: '二级 3-1',
            children: [{
              id: 11,
              label: '三级 3-1-1'
            }]
          }, {
            id: 12,
            label: '二级 3-2',
            children: [{
              id: 13,
              label: '三级 3-2-1'
            }]
          }]
        }
      ],
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      lazyProps: {
        label: 'name',
        children: 'zones',
        isLeaf: 'leaf'
      },
      count: 1
    } 
  },
  methods: {
    /**
     * @todo: 节点过滤方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:29:54
     * @param {*} value
     * @param {*} data
     * @param {*} node
     */
    handleFilterNode(value, data, node) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    /**
     * @todo: 节点点击响应方法
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 13:36:42
     * @param {*} data 树形结构数据中当前节点以及下一级子节点json对象
     * @param {*} node 节点对应的Node对象
     * @param {*} vnode 节点对应的Vue对象
     */
    handleNodeClick(data, node, vnode) {
      console.log(data);
    },
    /**
     * @todo: 懒加载方法
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 21:57:46
     * @param {*} node
     * @param {*} resolve
     */
    handleLoadNode(node, resolve) {
      // console.log(resolve);
      if (node.level === 0)
        return resolve([
          { name: '一级1', id: -1 },
          { name: '一级2', id: -2, leaf: true, disabled: true }
        ]);
      if (node.level > 3) return resolve([]);
      setTimeout(() => {
        var data;
        if (node.level === 3)
          data = [{
            id: this.count,
            name: '子节点' + this.count++,
            leaf: true
          }, {
            id: this.count,
            name: '子节点' + this.count++,
            leaf: true
          }];
        else
          data = [{
            id: this.count,
            name: '子节点' + this.count++
          }, {
            id: this.count,
            name: '子节点' + this.count++
          }];
        resolve(data);
      }, 500);
    },

    /**
     * @todo: 根据唯一id设置选中
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:13:18
     */
    setCheckedKeys() {
      console.log(this.$refs.tree1.$children[0]);
      this.$refs.tree1.$children[0].setCheckedKeys([3]);
    },
    /**
     * @todo: 根据唯一id设置选中(以node方式)
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:18:30
     */
    setCheckedNodes() {
      this.$refs.tree1.$children[0].setCheckedNodes([{
        id: 5
      }, {
        id: 9,
        label: '三级 1-1-1' // 主要是根据id判断选中
      }]);
    },
    /**
     * @todo: 返回选中的node(返回选中node对象数组)
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:20:56
     */
    getCheckedNodes() {
      console.log(this.$refs.tree1.$children[0].getCheckedNodes());
    },
    /**
     * @todo: 获取选中的id(返回选中id数组)
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:20:33
     */
    getCheckedKeys() {
      console.log(this.$refs.tree1.$children[0].getCheckedKeys());
    },
    /**
     * @todo: 重置选中
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:13:30
     */
    resetChecked() {
      this.$refs.tree1.$children[0].setCheckedKeys([]);
    }
  }
};
</script>
<style lang="scss" scoped>
.buttons{
  padding: 10px;

  .ht-button{
    margin: 10px 10px 10px 0;
  }
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
Expand Copy
懒加载

配置参数

是否复选 节点是否可拖拽
懒加载
<template>
  <ht-row style="width:100%;padding:10px 20px;">
    <ht-col :span="12">
      <!--
        tree-props:设置tree的节点和label属性
        node-key:设置tree节点的唯一key
        default-expanded-keys:设置默认展开的节点
        default-checked-keys:设置默认选中的节点
        draggable:设置tree是否可拖拽
        show-checkbox:设置tree是否多选
        lazy:设置tree是否懒加载
        load:设置懒加载的加载方法
        node-click:点击树节点响应事件
      -->
      <ht-tree
        ref="tree2" 
        :tree-props="lazyProps" 
        node-key="id"
        :default-expanded-keys="[2,3]" 
        :default-checked-keys="[5]" 
        :draggable="isDraggable" 
        :show-checkbox="showCheckbox" 
        :lazy="isLazy" 
        :load="handleLoadNode" 
        @node-click="handleNodeClick"
      />
    </ht-col>
    <ht-col :span="12">
      <div>
        <p>配置参数</p>
        <ht-checkbox v-model="showCheckbox">是否复选</ht-checkbox>
        <ht-checkbox v-model="isDraggable">节点是否可拖拽</ht-checkbox>
      </div>
    </ht-col>
  </ht-row>
</template>
<script>
export default {
  data() {
    return {
      filterText: '', // 树形过滤内容
      isDefaultExpandAll: true, // 默认是否全部展开
      showCheckbox: true, // 是否显示复选框
      isDraggable: false, // 节点是否可拖拽
      isLazy: true, // 是否懒加载
      treeData: [
        {
          id: 1,
          label: '一级 1',
          children: [{
            id: 2,
            label: '二级 1-1',
            children: [{
              id: 3,
              label: '三级 1-1-1'
            }]
          }]
        }, {
          id: 4,
          label: '一级 2',
          children: [{
            id: 5,
            label: '二级 2-1',
            children: [{
              id: 6,
              label: '三级 2-1-1'
            }]
          }, {
            id: 7,
            label: '二级 2-2',
            children: [{
              id: 8,
              label: '三级 2-2-1'
            }]
          }]
        }, {
          id: 9,
          label: '一级 3',
          children: [{
            id: 10,
            label: '二级 3-1',
            children: [{
              id: 11,
              label: '三级 3-1-1'
            }]
          }, {
            id: 12,
            label: '二级 3-2',
            children: [{
              id: 13,
              label: '三级 3-2-1'
            }]
          }]
        }
      ],
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      lazyProps: {
        label: 'name',
        children: 'zones',
        isLeaf: 'leaf'
      },
      count: 1
    } 
  },
  methods: {
    /**
     * @todo: 节点过滤方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:29:54
     * @param {*} value
     * @param {*} data
     * @param {*} node
     */
    handleFilterNode(value, data, node) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    /**
     * @todo: 节点点击响应方法
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 13:36:42
     * @param {*} data 树形结构数据中当前节点以及下一级子节点json对象
     * @param {*} node 节点对应的Node对象
     * @param {*} vnode 节点对应的Vue对象
     */
    handleNodeClick(data, node, vnode) {
      console.log(data);
    },
    /**
     * @todo: 懒加载方法
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 21:57:46
     * @param {*} node
     * @param {*} resolve
     */
    handleLoadNode(node, resolve) {
      // console.log(resolve);
      if (node.level === 0)
        return resolve([
          { name: '一级1', id: -1 },
          { name: '一级2', id: -2, leaf: true, disabled: true }
        ]);
      if (node.level > 3) return resolve([]);
      setTimeout(() => {
        var data;
        if (node.level === 3)
          data = [{
            id: this.count,
            name: '子节点' + this.count++,
            leaf: true
          }, {
            id: this.count,
            name: '子节点' + this.count++,
            leaf: true
          }];
        else
          data = [{
            id: this.count,
            name: '子节点' + this.count++
          }, {
            id: this.count,
            name: '子节点' + this.count++
          }];
        resolve(data);
      }, 500);
    },

    /**
     * @todo: 根据唯一id设置选中
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:13:18
     */
    setCheckedKeys() {
      console.log(this.$refs.tree1.$children[0]);
      this.$refs.tree1.$children[0].setCheckedKeys([3]);
    },
    /**
     * @todo: 根据唯一id设置选中(以node方式)
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:18:30
     */
    setCheckedNodes() {
      this.$refs.tree1.$children[0].setCheckedNodes([{
        id: 5
      }, {
        id: 9,
        label: '三级 1-1-1' // 主要是根据id判断选中
      }]);
    },
    /**
     * @todo: 返回选中的node(返回选中node对象数组)
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:20:56
     */
    getCheckedNodes() {
      console.log(this.$refs.tree1.$children[0].getCheckedNodes());
    },
    /**
     * @todo: 获取选中的id(返回选中id数组)
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:20:33
     */
    getCheckedKeys() {
      console.log(this.$refs.tree1.$children[0].getCheckedKeys());
    },
    /**
     * @todo: 重置选中
     * @author: andy.ten@tom.com & xukaixing@hotmail.com
     * @Date: 2022-07-02 22:13:30
     */
    resetChecked() {
      this.$refs.tree1.$children[0].setCheckedKeys([]);
    }
  }
};
</script>
<style lang="scss" scoped>
.buttons{
  padding: 10px;

  .ht-button{
    margin: 10px 10px 10px 0;
  }
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
Expand Copy

# 版本

  • v1.0.1