vue---实现递归组件(多级下拉菜单)
概念:组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事。之前在写组件时总有些疑惑,为什么export default导出的对象中有个name属性,今天看过递归组件之后,才发现这个name属性的一个比较重要的作用。(当然。name属性的还有其他的用处)。组件递归:1、设置组件name名称2、在模板中直接使用<名称 />xx-Yy的名称要写成<xxy
概念:
组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事。
之前在写组件时总有些疑惑,为什么export default导出的对象中有个name属性,今天看过递归组件之后,才发现这个name属性的一个比较重要的作用。(当然。name属性的还有其他的用处)。
组件递归:
1、设置组件name名称
2、在模板中直接使用
<名称 />
xx-Yy的名称要写成<xxyy />
3、使用时传入参数的方式和组件在其他组件中使用相同,注意递归终止条件
<xx :props="props"> 倘若组件需要传参数
用法:
1、首先我们要知道,既然是递归组件,那么一定要有一个结束的条件,否则就会使用组件循环引用,最终出现“max stack size exceeded”的错误,也就是栈溢出。那么,我们可以使用v-if="false"作为递归组件的结束条件。当遇到v-if为false时,组件将不会再进行渲染。
数据结构:
list: [
{
title: "成人票",
children: [
{
title: "成人三馆联票",
children: [
{
title: "嘉华酒店自助晚餐",
children: [
{
title: "嘉华酒店自助晚餐-武汉分店",
},
],
},
{
title: "文华酒店自助晚餐",
},
{
title: "君越酒店自助晚餐",
},
],
},
{
title: "成人五馆联票",
},
{
title: "成人五馆联票 + 酒店",
},
],
},
{
title: "学生票",
children: [
{
title: "古井酒店自助晚餐",
},
{
title: "维斯汀酒店自助晚餐",
},
{
title: "诺富特嘉华酒店自助晚餐",
},
{
title: "全季酒店自助晚餐",
},
],
},
{
title: "儿童票",
},
{
title: "特惠票",
},
],
递归组件:
<template>
<div class="detail-list">
<div class="item" v-for="(item, index) in list" :key="index">
<div class="item-title border-bottom" @click.stop="changeStatus(index)">
<span class="iconfont icon-round_ticket_fill"></span>
<span>{{ item.title }}</span>
</div>
<!-- 注意递归终止条件 -->
<div v-if="item.children" class="item-children">
<!-- 通过name进行递归调用 -->
<detail-list
v-if="scopesDefault[index]"
:list="item.children"
></detail-list>
</div>
</div>
</div>
</template>
<script>
export default {
name: "DetailList",
props: {
list: Array,
},
};
</script>
<style scoped>
.item-title {
line-height: 40px;
padding: 0 10px;
display: flex;
align-items: center;
color: #666;
}
.item-title .iconfont {
font-size: 18px;
margin-right: 5px;
color: rgb(0, 212, 227);
}
.item-children {
padding: 0 20px;
}
</style>
总结:
通过props从父组件拿到数据,递归组件每次进行递归的时候都会detail-list组件传递下一级children数据,(大家可以想象一下整个过程),整个过程结束之后,递归也就完成了,当然,这段代码只是简单的做了下递归组件的使用。对于折叠树状菜单来说,我们一般只会去渲染一级的数据,当点击一级菜单时,再去渲染一级菜单下的结构,如此往复。那么v-if就可以实现我们的这个需求,当v-if设置为false时,递归组件将不会再进行渲染,设置为true时,继续渲染
多级下拉菜单
最后也为大家准备了一个树状折叠菜单的递归组件实现方式~~
<template>
<div class="detail-list">
<div class="item" v-for="(item, index) in list" :key="index">
<div class="item-title border-bottom" @click.stop="changeStatus(index)">
<span class="iconfont icon-round_ticket_fill"></span>
<span>{{ item.title }}</span>
</div>
<!-- 注意递归终止条件 -->
<div v-if="item.children" class="item-children">
<!-- 通过name进行递归调用 -->
<detail-list
v-if="scopesDefault[index]"
:list="item.children"
></detail-list>
</div>
</div>
</div>
</template>
<script>
export default {
name: "DetailList",
props: {
list: Array,
},
data() {
return {
scopesDefault: [], // 第一级
scopes: [], // 第二级
};
},
created() {
this.scope();
},
methods: {
changeStatus(index) {
if (this.scopesDefault[index] == true) {
this.$set(this.scopesDefault, index, false);
} else {
this.$set(this.scopesDefault, index, this.scopes[index]);
}
},
scope() {
this.list.forEach((item, index) => {
this.scopesDefault[index] = false; // 第一级索引值全都是false
if ("children" in item) {// 判断第一级是否有children
this.scopes[index] = true;
} else {
this.scopes[index] = false;
}
});
},
},
};
</script>
<style scoped>
.item-title {
line-height: 40px;
padding: 0 10px;
display: flex;
align-items: center;
color: #666;
}
.item-title .iconfont {
font-size: 18px;
margin-right: 5px;
color: rgb(0, 212, 227);
}
.item-children {
padding: 0 20px;
}
</style>
更多推荐
所有评论(0)