树形组件在文件管理系统里很常见,大概类似:
实现树型组件主要是循环利用组件,用一个数组标记需要展开的是哪一个节点下面的内容,
App.vue
<template>
<tree :tree-data="treeData"></tree>
</template>
<script>
import Tree from './Tree'
export default {
data(){
return {
msg: 'hello',
treeData: [
{
name: 'node1',
children: [
{
name: 'node1-1',
children: [
{
name: 'node1-1-1',
children: []
},
{
name: 'node1-1-2',
children: []
},
{
name: 'node1-1-3',
children: []
},
]
},
{
name: 'node1-2',
children: [
{
name: 'node1-2-1',
children: []
},
{
name: 'node1-2-2',
children: []
},
]
},
{
name: 'node1-3',
children: []
}
]
},
{
name: 'node2',
children: [
{
name: 'node2-1',
children: []
},
{
name: 'node2-2',
children: [
{
name: 'node2-2-1',
children: []
},
{
name: 'node2-2-2',
children: []
}
]
},
{
name: 'node2-3',
children: [
{
name: 'node2-3-1',
children: []
},
{
name: 'node2-3-2',
children: []
},
]
}
]
}
]
}
},
components: {
Tree
}
}
</script>
Tree.vue
<template>
<ul class="tree">
<li v-for="(item, index) in treeData" :key="item.name" class="treeli" >
<span @click="handleClick(index)">{{item.name}}</span>
<!-- <ul v-if="showChildren[index]">
<li>kkkk</li>
</ul> -->
<tree v-show="showChildren[index]" v-if="alreadyShow[index]" :tree-data="item.children"></tree>
</li>
</ul>
</template>
<script>
export default {
name: 'tree',
data (){
return {
flag: false,
showChildren: [],//标记需要展开的是哪个节点
alreadyShow: []
}
},
methods: {
handleClick(index){
//通过索引的方法改变数组,值可以改变,但是不渲染,所以这种方法不行
// this.showChildren[index] = !this.showChildren[index];
this.showChildren.splice(index, 1, !this.showChildren[index]);
if(!this.alreadyShow[index]){
this.alreadyShow.splice(index, 1, true);
}
}
},
props:['tree-data']
}
</script>
<style scoped>
.treeli{
cursor: pointer;
}
</style>
这里面用了一个alreadyShow,来标记这个节点是否展开过了,如果展开过了,就保留在这,收起之后再打开也仍然保留。