本篇文章借鉴于此处,如果只需显示树形组件,可以直接访问该博主文章。我这里对他的组件做了扩展,增加了点击展开和关闭操作,话不多说上代码。
1.数据结构
const data = {label: '根目录',children: [{label: '目录A',children: [// 叶子节点{label: '目录A1'}]}, {label: '目录B'}]
2. 节点(Node.js)
<template><div ><div:class="isExpand === node.label?'parent active':'parent'":style="getLevelStyle(level)"@click="showChild(node)"><span>{{node.label}}</span><span v-show="!isNode()">></span></div><div v-show="!isNode() && isExpand === node.label"><!-- 在这里引用node自身,完成递归操作 --><node :node="node" v-for="(node, i) of node.children" :key="i" :level="level+1" v-bind="$attrs" v-on="$listeners"></node></div></div></template><script>
export default {name: 'Node',props: {node: Object,level: {type: Number,default: 0}},components: {// 这里不需要引用node自身},data() {return {isExpand: null}},methods: {isNode() {return !this.node.children || this.node.children.length === 0},showChild(node) {if (this.isNode()) {this.$emit('nodeClick', node)} else {if (this.isExpand === node.label) {this.isExpand = null} else {this.isExpand = node.label}}},getLevelStyle(level) {return { 'margin-left': level * 20 + 'px' }}}}
</script><style lang="scss" scoped>.parent {background: #F2F2F6;border-radius: 10px;padding: 12px;margin-bottom: 5px;display: flex;justify-content: space-between;}.active{background: #D3D3DC;}
</style>
3.组合成树(TreeNode.js)
<template><div style="padding: 20px 10px;"><Node :node="treeData" v-bind="$attrs" v-on="$listeners"></Node></div></template><script>
import Node from './Node'
export default {name: 'TreeNode',props: {treeData: Object},components: {Node},methods: {nodeClick(data) {this.$emit('nodeClick', data)}}}
</script><style scoped></style>
4.使用
<template><div><TreeNode :tree-data="treeData" @nodeClick="nodeClick"></TreeNode></div>
</template><script>
import TreeNode from "./TreeNode";
export default {name: 'HelloWorld',components: {TreeNode},data () {return {treeData: {label: 'A',children: [{label: 'A-1',children: [{label: 'A-1-1',children: [{label: 'A-1-1-1'},{label: 'A-1-1-2'}]},{label: 'A-1-2',children: [{label: 'A-1-2-1'}]},{label: 'A-1-3',children: [{label: 'A-1-3-1'}]}]}, {label: 'B-1',children: [{label: 'B-1-1'},{label: 'B-1-2'}]}]}}},methods:{nodeClick(data) {console.log('===========Node click', data)}}
}
</script><style scoped>
</style>
5. 显示效果
6. 总结
遇到一个难题就是子组件往最外层传递事件,在网上找到了答案,需要在内层组件加:
v-bind="$attrs" v-on="$listeners"
使用的地方不用加,这样最外层可以监听到子组件发出的事件。