递归组件的要求
1、数据的处理,数据一定要子级,也就是children数据,当递归组件的时候将每一项的 children 数据传给递归的组件的数据进行使用。每加一个children就会自动添加一个子级。
2、引入要递归的组件,在它的模板内可以递归地调用自己,不过,只有当它有 name 选项时才可以。一定要设置name属性也就是组件的名字。
3、一定要有递归的终止条件否则会死循环,“max stack size exceeded”的错误,也就是栈溢出。我们可以使用v-if="false"作为递归组件的结束条件。当遇到v-if为false时,组件将不会再进行渲染。
4、props一定要和传递组件的属性名字对上。可以设置props默认为数组。
创建一个treeIndex.vue的vue文件,为父组件
<template>
<div class="">
<!-- 递归组件将数据传进去 -->
<Tree :treeData="treeData"></Tree>
</div>
</template>
<script>
import Tree from './tree.vue';
export default {
data() {
return {
treeData: [
{
id: 432,
name: '一级数据-001-111',
isOpen: false,
children: [
{
id: 32,
name: '二级数据-002-111',
isOpen: false,
children: [
{
id: 532,
name: '三级数据-003-111',
isOpen: false,
},
{
id: 5326,
name: '三级数据-004-111',
isOpen: false,
},
],
},
{
id: 43,
name: '二级数据-001-111',
isOpen: false,
children: [
{
id: 41,
name: '三级数据-005-111',
isOpen: false,
},
{
id: 546,
name: '三级数据-006-111',
isOpen: false,
},
],
},
],
},
{
id: 42143,
name: '一级数据-007-222',
isOpen: false,
children: [
{
id: 5235,
name: '二级数据-008-222',
isOpen: false,
children: [
{
id: 5235423,
name: '三级数据-009-222',
isOpen: false,
},
{
id: 53252,
name: '三级数据-010-222',
isOpen: false,
},
],
},
{
id: 457,
name: '二级数据-011-222',
isOpen: false,
children: [
{
id: 5235423,
name: '三级数据-012-222',
isOpen: false,
},
{
id: 53252,
name: '三级数据-013-222',
isOpen: false,
},
],
},
],
},
],
};
},
mounted() {},
methods: {
},
components: { Tree },
};
</script>
<style lang="scss" scoped></style>
在创建一个子组件,也就是我们的递归组件,tree.vue
<template>
<ul>
<li
v-for="(item, index) in newTreeData"
:key="index"
@click.stop="openShow(item)"
>
<p>
<span
v-if="item.children && item.children.length > 0"
:class="['icon-triangle', item.isOpen ? 'rotate' : 'rotateFalse']"
></span>
<span>{
{ item.name }}</span>
</p>
<transition name="slide-fade">
<!-- 递归组件循环引用,要有终止条件 ,treeData再把子级传进去再次便利-->
<Tree
v-show="item.isOpen && item.children && item.children.length > 0"
:treeData="item.children"
></Tree>
</transition>
</li>
</ul>
</template>
<script>
import Tree from '@/views/tree/tree.vue';
export default {
props: {
treeData: {
type: Array,
default: () => [],
},
},
name: 'Tree', // 一定要设置name属性
data() {
return {
newTreeData: [],
};
},
mounted() {
this.newTreeData = this.treeData;
},
methods: {
openShow(item) {
this.$nextTick(() => {
item.isOpen = !item.isOpen; // 重新开启或者关闭
console.log(item)
});
},
},
components: { Tree },
};
</script>
<style lang="scss" scoped>
.icon-triangle {
display: inline-block;
border: 7px solid transparent;
border-bottom-color: #ccc;
transform: rotate(90deg);
&:hover {
cursor: pointer;
}
}
li {
margin-left: 22px;
margin-top: 13px;
&:hover {
cursor: pointer;
}
}
.rotate {
transform: rotate(180deg);
transition: all 0.5s;
position: relative;
top: 5px;
right: 5px;
}
.rotateFalse {
transform: rotate(90deg);
transition: all 0.2s;
}
/* 可以设置不同的进入和离开动画 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all 0.3s ease;
}
.slide-fade-leave-active {
transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active for below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
}
</style>
我是刷子哥