树形组件:用清晰的层级结构展示信息,可展开或折叠。
树组件使用挺频繁的,常见于侧边栏树形目录、树形下拉选项按钮或搜索查询树形信息选项
1.如何使用?
基础的树形结构展示
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree><script>export default {data() {return {data: [{label: '一级 1',children: [{label: '二级 1-1',children: [{label: '三级 1-1-1'}]}]}, {label: '一级 2',children: [{label: '二级 2-1',children: [{label: '三级 2-1-1'}]}, {label: '二级 2-2',children: [{label: '三级 2-2-1'}]}]}, {label: '一级 3',children: [{label: '二级 3-1',children: [{label: '三级 3-1-1'}]}, {label: '二级 3-2',children: [{label: '三级 3-2-1'}]}]}],defaultProps: {children: 'children',label: 'label'}};},methods: {handleNodeClick(data) {console.log(data);}}};
</script>
2.可选择
适用于需要选择层级时使用。
//可以动态加载节点数据。
<el-tree:props="props":load="loadNode"lazyshow-checkbox@check-change="handleCheckChange">
</el-tree><script>export default {data() {return {props: {label: 'name',children: 'zones'},count: 1};},methods: {handleCheckChange(data, checked, indeterminate) {console.log(data, checked, indeterminate);},handleNodeClick(data) {console.log(data);},loadNode(node, resolve) {if (node.level === 0) {return resolve([{ name: 'region1' }, { name: 'region2' }]);}if (node.level > 3) return resolve([]);var hasChild;if (node.data.name === 'region1') {hasChild = true;} else if (node.data.name === 'region2') {hasChild = false;} else {hasChild = Math.random() > 0.5;}setTimeout(() => {var data;if (hasChild) {data = [{name: 'zone' + this.count++}, {name: 'zone' + this.count++}];} else {data = [];}resolve(data);}, 500);}}};
</script>
3.懒加载自定义叶子节点
/*由于在点击节点时才进行该层数据的获取,默认情况下 Tree 无法预知某个节点是否为叶子节点,所以会为每个节点添加一个下拉按钮,如果节点没有下层数据,则点击后下拉按钮会消失。同时,你也可以提前告知 Tree 某个节点是否为叶子节点,从而避免在叶子节点前渲染下拉按钮。*/<el-tree:props="props":load="loadNode"lazyshow-checkbox>
</el-tree><script>export default {data() {return {props: {label: 'name',children: 'zones',isLeaf: 'leaf'},};},methods: {loadNode(node, resolve) {if (node.level === 0) {return resolve([{ name: 'region' }]);}if (node.level > 1) return resolve([]);setTimeout(() => {const data = [{name: 'leaf',leaf: true}, {name: 'zone'}];resolve(data);}, 500);}}};
</script>
4.默认展开和默认选中
可将 Tree 的某些节点设置为默认展开或默认选中
/*分别通过default-expanded-keys和default-checked-keys设置默认展开和默认选中的节点。需要注意的是,此时必须设置node-key,其值为节点数据中的一个字段名,该字段在整棵树中是唯一的。*/<el-tree:data="data"show-checkboxnode-key="id":default-expanded-keys="[2, 3]":default-checked-keys="[5]":props="defaultProps">
</el-tree><script>export default {data() {return {data: [{id: 1,label: '一级 1',children: [{id: 4,label: '二级 1-1',children: [{id: 9,label: '三级 1-1-1'}, {id: 10,label: '三级 1-1-2'}]}]}, {id: 2,label: '一级 2',children: [{id: 5,label: '二级 2-1'}, {id: 6,label: '二级 2-2'}]}, {id: 3,label: '一级 3',children: [{id: 7,label: '二级 3-1'}, {id: 8,label: '二级 3-2'}]}],defaultProps: {children: 'children',label: 'label'}};}};
</script>
5.禁用状态
可将 Tree 的某些节点设置为禁用状态
//通过disabled设置禁用状态。<el-tree:data="data"show-checkboxnode-key="id":default-expanded-keys="[2, 3]":default-checked-keys="[5]">
</el-tree><script>export default {data() {return {data: [{id: 1,label: '一级 2',children: [{id: 3,label: '二级 2-1',children: [{id: 4,label: '三级 3-1-1'}, {id: 5,label: '三级 3-1-2',disabled: true}]}, {id: 2,label: '二级 2-2',disabled: true,children: [{id: 6,label: '三级 3-2-1'}, {id: 7,label: '三级 3-2-2',disabled: true}]}]}],defaultProps: {children: 'children',label: 'label'}};}};
</script>
6.树节点的选择
/*如何获取和设置选中节点。获取和设置各有两种方式:通过 node 或通过 key。如果需要通过 key 来获取或设置,则必须设置node-key。*/<el-tree:data="data"show-checkboxdefault-expand-allnode-key="id"ref="tree"highlight-current:props="defaultProps">
</el-tree><div class="buttons"><el-button @click="getCheckedNodes">通过 node 获取</el-button><el-button @click="getCheckedKeys">通过 key 获取</el-button><el-button @click="setCheckedNodes">通过 node 设置</el-button><el-button @click="setCheckedKeys">通过 key 设置</el-button><el-button @click="resetChecked">清空</el-button>
</div><script>export default {methods: {getCheckedNodes() {console.log(this.$refs.tree.getCheckedNodes());},getCheckedKeys() {console.log(this.$refs.tree.getCheckedKeys());},setCheckedNodes() {this.$refs.tree.setCheckedNodes([{id: 5,label: '二级 2-1'}, {id: 9,label: '三级 1-1-1'}]);},setCheckedKeys() {this.$refs.tree.setCheckedKeys([3]);},resetChecked() {this.$refs.tree.setCheckedKeys([]);}},data() {return {data: [{id: 1,label: '一级 1',children: [{id: 4,label: '二级 1-1',children: [{id: 9,label: '三级 1-1-1'}, {id: 10,label: '三级 1-1-2'}]}]}, {id: 2,label: '一级 2',children: [{id: 5,label: '二级 2-1'}, {id: 6,label: '二级 2-2'}]}, {id: 3,label: '一级 3',children: [{id: 7,label: '二级 3-1'}, {id: 8,label: '二级 3-2'}]}],defaultProps: {children: 'children',label: 'label'}};}};
</script>
7.自定义节点内容
节点的内容支持自定义,可以在节点区添加按钮或图标等内容
/*可以通过两种方法进行树节点内容的自定义:render-content和 scoped slot。使用render-content指定渲染函数,该函数返回需要的节点区内容即可。渲染函数的用法请参考 Vue 文档。使用 scoped slot 会传入两个参数node和data,分别表示当前节点的 Node 对象和当前节点的数据。注意:由于 jsfiddle 不支持 JSX 语法,所以render-content示例在 jsfiddle 中无法运行。但是在实际的项目中,只要正确地配置了相关依赖,就可以正常运行。*/<div class="custom-tree-container"><div class="block"><p>使用 render-content</p><el-tree:data="data"show-checkboxnode-key="id"default-expand-all:expand-on-click-node="false":render-content="renderContent"></el-tree></div><div class="block"><p>使用 scoped slot</p><el-tree:data="data"show-checkboxnode-key="id"default-expand-all:expand-on-click-node="false"><span class="custom-tree-node" slot-scope="{ node, data }"><span>{{ node.label }}</span><span><el-buttontype="text"size="mini"@click="() => append(data)">Append</el-button><el-buttontype="text"size="mini"@click="() => remove(node, data)">Delete</el-button></span></span></el-tree></div>
</div><script>let id = 1000;export default {data() {const data = [{id: 1,label: '一级 1',children: [{id: 4,label: '二级 1-1',children: [{id: 9,label: '三级 1-1-1'}, {id: 10,label: '三级 1-1-2'}]}]}, {id: 2,label: '一级 2',children: [{id: 5,label: '二级 2-1'}, {id: 6,label: '二级 2-2'}]}, {id: 3,label: '一级 3',children: [{id: 7,label: '二级 3-1'}, {id: 8,label: '二级 3-2'}]}];return {data: JSON.parse(JSON.stringify(data)),data: JSON.parse(JSON.stringify(data))}},methods: {append(data) {const newChild = { id: id++, label: 'testtest', children: [] };if (!data.children) {this.$set(data, 'children', []);}data.children.push(newChild);},remove(node, data) {const parent = node.parent;const children = parent.data.children || parent.data;const index = children.findIndex(d => d.id === data.id);children.splice(index, 1);},renderContent(h, { node, data, store }) {return (<span class="custom-tree-node"><span>{node.label}</span><span><el-button size="mini" type="text" on-click={ () => this.append(data) }>Append</el-button><el-button size="mini" type="text" on-click={ () => this.remove(node, data) }>Delete</el-button></span></span>);}}};
</script><style>.custom-tree-node {flex: 1;display: flex;align-items: center;justify-content: space-between;font-size: 14px;padding-right: 8px;}
</style>
8.节点过滤
通过关键字过滤树节点
/*在需要对节点进行过滤时,调用 Tree 实例的filter方法,参数为关键字。需要注意的是,此时需要设置filter-node-method,值为过滤函数。*/<el-inputplaceholder="输入关键字进行过滤"v-model="filterText">
</el-input><el-treeclass="filter-tree":data="data":props="defaultProps"default-expand-all:filter-node-method="filterNode"ref="tree">
</el-tree><script>export default {watch: {filterText(val) {this.$refs.tree.filter(val);}},methods: {filterNode(value, data) {if (!value) return true;return data.label.indexOf(value) !== -1;}},data() {return {filterText: '',data: [{id: 1,label: '一级 1',children: [{id: 4,label: '二级 1-1',children: [{id: 9,label: '三级 1-1-1'}, {id: 10,label: '三级 1-1-2'}]}]}, {id: 2,label: '一级 2',children: [{id: 5,label: '二级 2-1'}, {id: 6,label: '二级 2-2'}]}, {id: 3,label: '一级 3',children: [{id: 7,label: '二级 3-1'}, {id: 8,label: '二级 3-2'}]}],defaultProps: {children: 'children',label: 'label'}};}};
</script>
9.手风琴模式
对于同一级的节点,每次只能展开一个
<el-tree:data="data":props="defaultProps"accordion@node-click="handleNodeClick">
</el-tree><script>export default {data() {return {data: [{label: '一级 1',children: [{label: '二级 1-1',children: [{label: '三级 1-1-1'}]}]}, {label: '一级 2',children: [{label: '二级 2-1',children: [{label: '三级 2-1-1'}]}, {label: '二级 2-2',children: [{label: '三级 2-2-1'}]}]}, {label: '一级 3',children: [{label: '二级 3-1',children: [{label: '三级 3-1-1'}]}, {label: '二级 3-2',children: [{label: '三级 3-2-1'}]}]}],defaultProps: {children: 'children',label: 'label'}};},methods: {handleNodeClick(data) {console.log(data);}}};
</script>
10.可拖拽节点
通过 draggable 属性可让节点变为可拖拽。
<el-tree:data="data"node-key="id"default-expand-all@node-drag-start="handleDragStart"@node-drag-enter="handleDragEnter"@node-drag-leave="handleDragLeave"@node-drag-over="handleDragOver"@node-drag-end="handleDragEnd"@node-drop="handleDrop"draggable:allow-drop="allowDrop":allow-drag="allowDrag">
</el-tree><script>export default {data() {return {data: [{id: 1,label: '一级 1',children: [{id: 4,label: '二级 1-1',children: [{id: 9,label: '三级 1-1-1'}, {id: 10,label: '三级 1-1-2'}]}]}, {id: 2,label: '一级 2',children: [{id: 5,label: '二级 2-1'}, {id: 6,label: '二级 2-2'}]}, {id: 3,label: '一级 3',children: [{id: 7,label: '二级 3-1'}, {id: 8,label: '二级 3-2',children: [{id: 11,label: '三级 3-2-1'}, {id: 12,label: '三级 3-2-2'}, {id: 13,label: '三级 3-2-3'}]}]}],defaultProps: {children: 'children',label: 'label'}};},methods: {handleDragStart(node, ev) {console.log('drag start', node);},handleDragEnter(draggingNode, dropNode, ev) {console.log('tree drag enter: ', dropNode.label);},handleDragLeave(draggingNode, dropNode, ev) {console.log('tree drag leave: ', dropNode.label);},handleDragOver(draggingNode, dropNode, ev) {console.log('tree drag over: ', dropNode.label);},handleDragEnd(draggingNode, dropNode, dropType, ev) {console.log('tree drag end: ', dropNode && dropNode.label, dropType);},handleDrop(draggingNode, dropNode, dropType, ev) {console.log('tree drop: ', dropNode.label, dropType);},allowDrop(draggingNode, dropNode, type) {if (dropNode.data.label === '二级 3-1') {return type !== 'inner';} else {return true;}},allowDrag(draggingNode) {return draggingNode.data.label.indexOf('三级 3-2-2') === -1;}}};
</script>
上述内容即为Tree树组件的详细使用方法,若想深入浅出可以前往Tree组件 。