Tree 树形控件
用清晰的层级结构展示信息,可展开或折叠。
基础用法
基础的树形结构展示。
1 <el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree> 2 3 <script> 4 export default { 5 data() { 6 return { 7 data: [{ 8 label: '一级 1', 9 children: [{ 10 label: '二级 1-1', 11 children: [{ 12 label: '三级 1-1-1' 13 }] 14 }] 15 }, { 16 label: '一级 2', 17 children: [{ 18 label: '二级 2-1', 19 children: [{ 20 label: '三级 2-1-1' 21 }] 22 }, { 23 label: '二级 2-2', 24 children: [{ 25 label: '三级 2-2-1' 26 }] 27 }] 28 }, { 29 label: '一级 3', 30 children: [{ 31 label: '二级 3-1', 32 children: [{ 33 label: '三级 3-1-1' 34 }] 35 }, { 36 label: '二级 3-2', 37 children: [{ 38 label: '三级 3-2-1' 39 }] 40 }] 41 }], 42 defaultProps: { 43 children: 'children', 44 label: 'label' 45 } 46 }; 47 }, 48 methods: { 49 handleNodeClick(data) { 50 console.log(data); 51 } 52 } 53 }; 54 </script>
可选择
适用于需要选择层级时使用。
本例还展示了动态加载节点数据的方法。
1 <el-tree 2 :props="props" 3 :load="loadNode" 4 lazy 5 show-checkbox 6 @check-change="handleCheckChange"> 7 </el-tree> 8 9 <script> 10 export default { 11 data() { 12 return { 13 props: { 14 label: 'name', 15 children: 'zones' 16 }, 17 count: 1 18 }; 19 }, 20 methods: { 21 handleCheckChange(data, checked, indeterminate) { 22 console.log(data, checked, indeterminate); 23 }, 24 handleNodeClick(data) { 25 console.log(data); 26 }, 27 loadNode(node, resolve) { 28 if (node.level === 0) { 29 return resolve([{ name: 'region1' }, { name: 'region2' }]); 30 } 31 if (node.level > 3) return resolve([]); 32 33 var hasChild; 34 if (node.data.name === 'region1') { 35 hasChild = true; 36 } else if (node.data.name === 'region2') { 37 hasChild = false; 38 } else { 39 hasChild = Math.random() > 0.5; 40 } 41 42 setTimeout(() => { 43 var data; 44 if (hasChild) { 45 data = [{ 46 name: 'zone' + this.count++ 47 }, { 48 name: 'zone' + this.count++ 49 }]; 50 } else { 51 data = []; 52 } 53 54 resolve(data); 55 }, 500); 56 } 57 } 58 }; 59 </script>
懒加载自定义叶子节点
由于在点击节点时才进行该层数据的获取,默认情况下 Tree 无法预知某个节点是否为叶子节点,所以会为每个节点添加一个下拉按钮,如果节点没有下层数据,则点击后下拉按钮会消失。同时,你也可以提前告知 Tree 某个节点是否为叶子节点,从而避免在叶子节点前渲染下拉按钮。
1 <el-tree 2 :props="props1" 3 :load="loadNode1" 4 lazy 5 show-checkbox> 6 </el-tree> 7 8 <script> 9 export default { 10 data() { 11 return { 12 props1: { 13 label: 'name', 14 children: 'zones', 15 isLeaf: 'leaf' 16 }, 17 }; 18 }, 19 methods: { 20 loadNode1(node, resolve) { 21 if (node.level === 0) { 22 return resolve([{ name: 'region' }]); 23 } 24 if (node.level > 1) return resolve([]); 25 26 setTimeout(() => { 27 const data = [{ 28 name: 'leaf', 29 leaf: true 30 }, { 31 name: 'zone' 32 }]; 33 34 resolve(data); 35 }, 500); 36 } 37 } 38 }; 39 </script>
默认展开和默认选中
可将 Tree 的某些节点设置为默认展开或默认选中
分别通过default-expanded-keys
和default-checked-keys
设置默认展开和默认选中的节点。需要注意的是,此时必须设置node-key
,其值为节点数据中的一个字段名,该字段在整棵树中是唯一的。
1 <el-tree 2 :data="data2" 3 show-checkbox 4 node-key="id" 5 :default-expanded-keys="[2, 3]" 6 :default-checked-keys="[5]" 7 :props="defaultProps"> 8 </el-tree> 9 10 <script> 11 export default { 12 data() { 13 return { 14 data2: [{ 15 id: 1, 16 label: '一级 1', 17 children: [{ 18 id: 4, 19 label: '二级 1-1', 20 children: [{ 21 id: 9, 22 label: '三级 1-1-1' 23 }, { 24 id: 10, 25 label: '三级 1-1-2' 26 }] 27 }] 28 }, { 29 id: 2, 30 label: '一级 2', 31 children: [{ 32 id: 5, 33 label: '二级 2-1' 34 }, { 35 id: 6, 36 label: '二级 2-2' 37 }] 38 }, { 39 id: 3, 40 label: '一级 3', 41 children: [{ 42 id: 7, 43 label: '二级 3-1' 44 }, { 45 id: 8, 46 label: '二级 3-2' 47 }] 48 }], 49 defaultProps: { 50 children: 'children', 51 label: 'label' 52 } 53 }; 54 } 55 }; 56 </script>
禁用状态
可将 Tree 的某些节点设置为禁用状态
通过disabled
设置禁用状态。
1 <el-tree 2 :data="data3" 3 show-checkbox 4 node-key="id" 5 :default-expanded-keys="[2, 3]" 6 :default-checked-keys="[5]"> 7 </el-tree> 8 9 <script> 10 export default { 11 data() { 12 return { 13 data3: [{ 14 id: 1, 15 label: '一级 2', 16 children: [{ 17 id: 3, 18 label: '二级 2-1', 19 children: [{ 20 id: 4, 21 label: '三级 3-1-1' 22 }, { 23 id: 5, 24 label: '三级 3-1-2', 25 disabled: true 26 }] 27 }, { 28 id: 2, 29 label: '二级 2-2', 30 disabled: true, 31 children: [{ 32 id: 6, 33 label: '三级 3-2-1' 34 }, { 35 id: 7, 36 label: '三级 3-2-2', 37 disabled: true 38 }] 39 }] 40 }], 41 defaultProps: { 42 children: 'children', 43 label: 'label' 44 } 45 }; 46 } 47 }; 48 </script>
树节点的选择
本例展示如何获取和设置选中节点。获取和设置各有两种方式:通过 node 或通过 key。如果需要通过 key 来获取或设置,则必须设置node-key
。
1 <el-tree 2 :data="data2" 3 show-checkbox 4 default-expand-all 5 node-key="id" 6 ref="tree" 7 highlight-current 8 :props="defaultProps"> 9 </el-tree> 10 11 <div class="buttons"> 12 <el-button @click="getCheckedNodes">通过 node 获取</el-button> 13 <el-button @click="getCheckedKeys">通过 key 获取</el-button> 14 <el-button @click="setCheckedNodes">通过 node 设置</el-button> 15 <el-button @click="setCheckedKeys">通过 key 设置</el-button> 16 <el-button @click="resetChecked">清空</el-button> 17 </div> 18 19 <script> 20 export default { 21 methods: { 22 getCheckedNodes() { 23 console.log(this.$refs.tree.getCheckedNodes()); 24 }, 25 getCheckedKeys() { 26 console.log(this.$refs.tree.getCheckedKeys()); 27 }, 28 setCheckedNodes() { 29 this.$refs.tree.setCheckedNodes([{ 30 id: 5, 31 label: '二级 2-1' 32 }, { 33 id: 9, 34 label: '三级 1-1-1' 35 }]); 36 }, 37 setCheckedKeys() { 38 this.$refs.tree.setCheckedKeys([3]); 39 }, 40 resetChecked() { 41 this.$refs.tree.setCheckedKeys([]); 42 } 43 }, 44 45 data() { 46 return { 47 data2: [{ 48 id: 1, 49 label: '一级 1', 50 children: [{ 51 id: 4, 52 label: '二级 1-1', 53 children: [{ 54 id: 9, 55 label: '三级 1-1-1' 56 }, { 57 id: 10, 58 label: '三级 1-1-2' 59 }] 60 }] 61 }, { 62 id: 2, 63 label: '一级 2', 64 children: [{ 65 id: 5, 66 label: '二级 2-1' 67 }, { 68 id: 6, 69 label: '二级 2-2' 70 }] 71 }, { 72 id: 3, 73 label: '一级 3', 74 children: [{ 75 id: 7, 76 label: '二级 3-1' 77 }, { 78 id: 8, 79 label: '二级 3-2' 80 }] 81 }], 82 defaultProps: { 83 children: 'children', 84 label: 'label' 85 } 86 }; 87 } 88 }; 89 </script>
自定义节点内容
节点的内容支持自定义,可以在节点区添加按钮或图标等内容
可以通过两种方法进行树节点内容的自定义:render-content
和 scoped slot。使用render-content
指定渲染函数,该函数返回需要的节点区内容即可。渲染函数的用法请参考 Vue 文档。使用 scoped slot 会传入两个参数node
和data
,分别表示当前节点的 Node 对象和当前节点的数据。注意:由于 jsfiddle 不支持 JSX 语法,所以render-content
示例在 jsfiddle 中无法运行。但是在实际的项目中,只要正确地配置了相关依赖,就可以正常运行。
1 <div class="custom-tree-container"> 2 <div class="block"> 3 <p>使用 render-content</p> 4 <el-tree 5 :data="data4" 6 show-checkbox 7 node-key="id" 8 default-expand-all 9 :expand-on-click-node="false" 10 :render-content="renderContent"> 11 </el-tree> 12 </div> 13 <div class="block"> 14 <p>使用 scoped slot</p> 15 <el-tree 16 :data="data5" 17 show-checkbox 18 node-key="id" 19 default-expand-all 20 :expand-on-click-node="false"> 21 <span class="custom-tree-node" slot-scope="{ node, data }"> 22 <span>{{ node.label }}</span> 23 <span> 24 <el-button 25 type="text" 26 size="mini" 27 @click="() => append(data)"> 28 Append 29 </el-button> 30 <el-button 31 type="text" 32 size="mini" 33 @click="() => remove(node, data)"> 34 Delete 35 </el-button> 36 </span> 37 </span> 38 </el-tree> 39 </div> 40 </div> 41 42 <script> 43 let id = 1000; 44 45 export default { 46 data() { 47 const data = [{ 48 id: 1, 49 label: '一级 1', 50 children: [{ 51 id: 4, 52 label: '二级 1-1', 53 children: [{ 54 id: 9, 55 label: '三级 1-1-1' 56 }, { 57 id: 10, 58 label: '三级 1-1-2' 59 }] 60 }] 61 }, { 62 id: 2, 63 label: '一级 2', 64 children: [{ 65 id: 5, 66 label: '二级 2-1' 67 }, { 68 id: 6, 69 label: '二级 2-2' 70 }] 71 }, { 72 id: 3, 73 label: '一级 3', 74 children: [{ 75 id: 7, 76 label: '二级 3-1' 77 }, { 78 id: 8, 79 label: '二级 3-2' 80 }] 81 }]; 82 return { 83 data4: JSON.parse(JSON.stringify(data)), 84 data5: JSON.parse(JSON.stringify(data)) 85 } 86 }, 87 88 methods: { 89 append(data) { 90 const newChild = { id: id++, label: 'testtest', children: [] }; 91 if (!data.children) { 92 this.$set(data, 'children', []); 93 } 94 data.children.push(newChild); 95 }, 96 97 remove(node, data) { 98 const parent = node.parent; 99 const children = parent.data.children || parent.data; 100 const index = children.findIndex(d => d.id === data.id); 101 children.splice(index, 1); 102 }, 103 104 renderContent(h, { node, data, store }) { 105 return ( 106 <span class="custom-tree-node"> 107 <span>{node.label}</span> 108 <span> 109 <el-button size="mini" type="text" on-click={ () => this.append(data) }>Append</el-button> 110 <el-button size="mini" type="text" on-click={ () => this.remove(node, data) }>Delete</el-button> 111 </span> 112 </span>); 113 } 114 } 115 }; 116 </script> 117 118 <style> 119 .custom-tree-node { 120 flex: 1; 121 display: flex; 122 align-items: center; 123 justify-content: space-between; 124 font-size: 14px; 125 padding-right: 8px; 126 } 127 </style>
节点过滤
通过关键字过滤树节点
在需要对节点进行过滤时,调用 Tree 实例的filter
方法,参数为关键字。需要注意的是,此时需要设置filter-node-method
,值为过滤函数。
1 <el-input 2 placeholder="输入关键字进行过滤" 3 v-model="filterText"> 4 </el-input> 5 6 <el-tree 7 class="filter-tree" 8 :data="data2" 9 :props="defaultProps" 10 default-expand-all 11 :filter-node-method="filterNode" 12 ref="tree2"> 13 </el-tree> 14 15 <script> 16 export default { 17 watch: { 18 filterText(val) { 19 this.$refs.tree2.filter(val); 20 } 21 }, 22 23 methods: { 24 filterNode(value, data) { 25 if (!value) return true; 26 return data.label.indexOf(value) !== -1; 27 } 28 }, 29 30 data() { 31 return { 32 filterText: '', 33 data2: [{ 34 id: 1, 35 label: '一级 1', 36 children: [{ 37 id: 4, 38 label: '二级 1-1', 39 children: [{ 40 id: 9, 41 label: '三级 1-1-1' 42 }, { 43 id: 10, 44 label: '三级 1-1-2' 45 }] 46 }] 47 }, { 48 id: 2, 49 label: '一级 2', 50 children: [{ 51 id: 5, 52 label: '二级 2-1' 53 }, { 54 id: 6, 55 label: '二级 2-2' 56 }] 57 }, { 58 id: 3, 59 label: '一级 3', 60 children: [{ 61 id: 7, 62 label: '二级 3-1' 63 }, { 64 id: 8, 65 label: '二级 3-2' 66 }] 67 }], 68 defaultProps: { 69 children: 'children', 70 label: 'label' 71 } 72 }; 73 } 74 }; 75 </script>
手风琴模式
对于同一级的节点,每次只能展开一个
1 <el-tree 2 :data="data" 3 :props="defaultProps" 4 accordion 5 @node-click="handleNodeClick"> 6 </el-tree> 7 8 <script> 9 export default { 10 data() { 11 return { 12 data: [{ 13 label: '一级 1', 14 children: [{ 15 label: '二级 1-1', 16 children: [{ 17 label: '三级 1-1-1' 18 }] 19 }] 20 }, { 21 label: '一级 2', 22 children: [{ 23 label: '二级 2-1', 24 children: [{ 25 label: '三级 2-1-1' 26 }] 27 }, { 28 label: '二级 2-2', 29 children: [{ 30 label: '三级 2-2-1' 31 }] 32 }] 33 }, { 34 label: '一级 3', 35 children: [{ 36 label: '二级 3-1', 37 children: [{ 38 label: '三级 3-1-1' 39 }] 40 }, { 41 label: '二级 3-2', 42 children: [{ 43 label: '三级 3-2-1' 44 }] 45 }] 46 }], 47 defaultProps: { 48 children: 'children', 49 label: 'label' 50 } 51 }; 52 }, 53 methods: { 54 handleNodeClick(data) { 55 console.log(data); 56 } 57 } 58 }; 59 </script>
Attributes
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
data | 展示数据 | array | — | — |
empty-text | 内容为空的时候展示的文本 | String | — | — |
node-key | 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 | String | — | — |
props | 配置选项,具体看下表 | object | — | — |
render-after-expand | 是否在第一次展开某个树节点后才渲染其子节点 | boolean | — | true |
load | 加载子树数据的方法,仅当 lazy 属性为true 时生效 | function(node, resolve) | — | — |
render-content | 树节点的内容区的渲染 Function | Function(h, { node, data, store } | — | — |
highlight-current | 是否高亮当前选中节点,默认值是 false。 | boolean | — | false |
default-expand-all | 是否默认展开所有节点 | boolean | — | false |
expand-on-click-node | 是否在点击节点的时候展开或者收缩节点, 默认值为 true,如果为 false,则只有点箭头图标的时候才会展开或者收缩节点。 | boolean | — | true |
auto-expand-parent | 展开子节点的时候是否自动展开父节点 | boolean | — | true |
default-expanded-keys | 默认展开的节点的 key 的数组 | array | — | — |
show-checkbox | 节点是否可被选择 | boolean | — | false |
check-strictly | 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false | boolean | — | false |
default-checked-keys | 默认勾选的节点的 key 的数组 | array | — | — |
filter-node-method | 对树节点进行筛选时执行的方法,返回 true 表示这个节点可以显示,返回 false 则表示这个节点会被隐藏 | Function(value, data, node) | — | — |
accordion | 是否每次只打开一个同级树节点展开 | boolean | — | false |
indent | 相邻级节点间的水平缩进,单位为像素 | number | — | 16 |
lazy | 是否懒加载子节点,需与 load 方法结合使用 | boolean | — | false |
props
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
label | 指定节点标签为节点对象的某个属性值 | string, function(data, node) | — | — |
children | 指定子树为节点对象的某个属性值 | string | — | — |
disabled | 指定节点选择框是否禁用为节点对象的某个属性值 | boolean, function(data, node) | — | — |
isLeaf | 指定节点是否为叶子节点,仅在指定了 lazy 属性的情况下生效 | boolean, function(data, node) | — | — |
方法
Tree
内部使用了 Node 类型的对象来包装用户传入的数据,用来保存目前节点的状态。 Tree
拥有如下方法:
方法名 | 说明 | 参数 |
---|---|---|
filter | 对树节点进行筛选操作 | 接收一个任意类型的参数,该参数会在 filter-node-method 中作为第一个参数 |
updateKeyChildren | 通过 keys 设置节点子元素,使用此方法必须设置 node-key 属性 | (key, data) 接收两个参数,1. 节点 key 2. 节点数据的数组 |
getCheckedNodes | 若节点可被选择(即 show-checkbox 为 true ),则返回目前被选中的节点所组成的数组 |
(leafOnly) 接收一个 boolean 类型的参数,若为 true 则仅返回被选中的叶子节点,默认值为 false |
setCheckedNodes | 设置目前勾选的节点,使用此方法必须设置 node-key 属性 | (nodes) 接收勾选节点数据的数组 |
getCheckedKeys | 若节点可被选择(即 show-checkbox 为 true ),则返回目前被选中的节点的 key 所组成的数组 |
(leafOnly) 接收一个 boolean 类型的参数,若为 true 则仅返回被选中的叶子节点的 keys,默认值为 false |
setCheckedKeys | 通过 keys 设置目前勾选的节点,使用此方法必须设置 node-key 属性 | (keys, leafOnly) 接收两个参数,1. 勾选节点的 key 的数组 2. boolean 类型的参数,若为 true 则仅设置叶子节点的选中状态,默认值为 false |
setChecked | 通过 key / data 设置某个节点的勾选状态,使用此方法必须设置 node-key 属性 | (key/data, checked, deep) 接收三个参数,1. 勾选节点的 key 或者 data 2. boolean 类型,节点是否选中 3. boolean 类型,是否设置子节点 ,默认为 false |
getHalfCheckedNodes | 若节点可被选择(即 show-checkbox 为 true ),则返回目前半选中的节点所组成的数组 |
- |
getHalfCheckedKeys | 若节点可被选择(即 show-checkbox 为 true ),则返回目前半选中的节点的 key 所组成的数组 |
- |
getCurrentKey | 获取当前被选中节点的 key,使用此方法必须设置 node-key 属性,若没有节点被选中则返回 null | — |
getCurrentNode | 获取当前被选中节点的 node,若没有节点被选中则返回 null | — |
setCurrentKey | 通过 key 设置某个节点的当前选中状态,使用此方法必须设置 node-key 属性 | (key) 待被选节点的 key |
setCurrentNode | 通过 node 设置某个节点的当前选中状态,使用此方法必须设置 node-key 属性 | (node) 待被选节点的 node |
getNode | 根据 data 或者 key 拿到 Tree 组件中的 node | (data) 要获得 node 的 key 或者 data |
remove | 删除 Tree 中的一个节点 | (data) 要删除的节点的 data、key 或者 node |
append | 为 Tree 中的一个节点追加一个子节点 | (data, parentNode) 接收两个参数,1. 要追加的子节点的 data 2. 子节点的 parent 的 data、key 或者 node |
insertBefore | 为 Tree 的一个节点的前面增加一个节点 | (data, refNode) 接收两个参数,1. 要增加的节点的 data 2. 要增加的节点的后一个节点的 data、key 或者 node |
insertAfter | 为 Tree 的一个节点的后面增加一个节点 | (data, refNode) 接收两个参数,1. 要增加的节点的 data 2. 要增加的节点的前一个节点的 data、key 或者 node |
Events
事件名称 | 说明 | 回调参数 |
---|---|---|
node-click | 节点被点击时的回调 | 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。 |
node-contextmenu | 当某一节点被鼠标右键点击时会触发该事件 | 共四个参数,依次为:event、传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。 |
check-change | 节点选中状态发生变化时的回调 | 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点本身是否被选中、节点的子树中是否有被选中的节点 |
check | 当复选框被点击的时候触发 | 共两个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、树目前的选中状态对象,包含 checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四个属性 |
current-change | 当前选中节点变化时触发的事件 | 共两个参数,依次为:当前节点的数据,当前节点的 Node 对象 |
node-expand | 节点被展开时触发的事件 | 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。 |
node-collapse | 节点被关闭时触发的事件 | 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。 |
Scoped slot
name | 说明 |
---|---|
— | 自定义树节点的内容,参数为 { node, data } |