概念
组件在它的模板内可以递归的调用自己,只要给组件设置name
就可以了
用法
设置name后,在组件模板内就可以递归使用了,不过需要注意的是,必须给一个条件来限制递归数量,否则会抛出错误:max stack size exceeded
- 父组件
在父组件中定义一个要递归的数据(list数组)
,通过props
传递给子组件
const vm = new Vue({
el: '#app',
data: {
msg: '我是来自父组件数据',
list: [
{
name: 1,
clist: [
{
name: 2,
clist: [
{
name: 3
}
]
},
],
},
]
},
created() { },
methods: {
}
})
- 子组件
定义一个name为com的子组件
Vue.component('com', {
template: `<div>
<div v-for="(item, index) in list" :key="index">
<p>{{item.name}}</p>
<com :list="item.clist"></com>
</div>
</div>`,
props: {
list: {
type: Array,
}
},
data() {
return {
message: '我是子组件',
};
},
created() { },
methods: {},
});
使用组件递归可以用来开发一些具有未知层级关系
的独立组件,比如
- 级联选择器
- 树形控件
- 导航菜单
- …
案例
使用递归组件创建导航菜单
- 父组件
<template>
<div class="nav">
<el-aside class="aside" style="width:100%">
<el-menu
:default-active="active"
class="el-menu-vertical-demo"
background-color="#3A3D4C"
text-color="#fff"
active-text-color="#01a5a7"
:collapse="isCollapse"
unique-opened
router
>
<NavItem v-for="v in navList" :key="v.path" :item="v" :basePath="v.path" :showIcon="true"></NavItem>
</el-menu>
</el-aside>
</div>
</template>
<script>
import NavItem from "./NavItem";
export default {
data() {
return {
isCollapse: false, // 是否水平折叠收起菜单
active: "/home", // 高亮显示的路由
navList: [
{
title: "首页",
path: "/home",
icon: "el-icon-menu",
},
{
title: "vue",
path: "",
subMenu: [
{
title: "MVVM",
path: "/mvvm",
},
{
title: "过滤器",
path: "/filter",
},
{
title: "指令",
path: "/directive",
},
{
title: "按键修饰符",
path: "/keyModifier",
},
],
},
{
title: "echarts图表",
path: "/",
subMenu: [
{
title: "折线图",
path: "/lineEcharts",
},
{
title: "K线图",
path: "/kEcharts",
},
],
},
],
};
},
components: {
NavItem,
},
created() {
// 刷新页面后,当前路由下的导航菜单高亮显示
this.active = this.$route.path;
},
methods: {
handleMenu() {
this.isCollapse = !this.isCollapse;
if (this.isCollapse) {
this.$notify({
title: "成功",
message: "已折叠菜单栏",
type: "success",
});
} else {
this.$notify({
title: "成功",
message: "已打开菜单栏",
type: "success",
});
}
},
},
};
</script>
<style scoped>
.aside {
height: calc(100vh - 60px);
color: #fff;
box-sizing: border-box;
overflow-x: hidden;
/* 隐藏滚动条 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE 10+ */
}
/* 隐藏滚动条 */
::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
.menu {
text-align: left;
}
</style>
<style>
.el-menu-vertical-demo {
padding-top: 30px;
height: calc(100vh - 60px);
box-sizing: border-box;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 210px;
min-height: 400px;
}
</style>
- 子组件
<template>
<!-- 使用fragment解决组件递归菜单栏不能折叠的问题 -->
<!-- 递归的时候外面套了一层div(不套div不行模板没有根),element的css选择器就找不里面的span了和那个小箭头了 -->
<!-- 因为element用的选择器是子类选择器一层一层找的,递归的时候多加了一层div,选择器就找不到了 -->
<!-- 此处使用fragment代替div,因为fragment编码但不渲染成标签 -->
<fragment>
<!-- 无子集 -->
<el-menu-item :index="basePath" v-if="!item.subMenu">
<i :class="item.icon" v-if="showIcon"></i>
<span slot="title">{{item.title}}</span>
</el-menu-item>
<!-- 有子集 -->
<el-submenu :index="basePath" v-else>
<template slot="title">
<i class="el-icon-location"></i>
<span>{{item.title}}</span>
</template>
<NavItem
v-for="ite in item.subMenu"
:key="ite.url"
:item="ite"
:basePath="ite.path"
:showIcon="false"
/>
</el-submenu>
</fragment>
</template>
<script>
export default {
name: "NavItem",
data() {
return {};
},
props: ["item", "basePath", "showIcon"],
};
</script>