如果菜单嵌套层数是已知的可以通过 v-for 循环出要渲染的菜单,但是如果我们不知道我们要循环多少层子菜单,那么这个时候 v-for 就不能解决问题了
要实现动态的渲染我们拿到的不知道有几层的菜单数据,有两种解决方案:
- 操作 dom 去一层一层 添加子菜单(vue 不推荐操作 dom,所以不推荐此方案)
- 将我们的菜单封装到组件中,通过递归组件实现菜单渲染
先贴一个 demo
demo地址:https://download.csdn.net/download/qq_25992675/12853870
- 动态的渲染菜单
- 可以通过点击菜单渲染加载子菜单
其实组件递归很简单,在组件中调用自己不需要引入注册自己,只需要通过组件的 name 在页面中通过标签的形式调用自己即可
组件递归的使用
这里只是贴的代码片段主要是介绍组件递归的使用,想看完整demo的可以下载demo
组件声明
注意点:
- Menu:组件的 name,可以通过定义的 name: “Menu” 作为标签来调用自己
- 要给组件加上 @click.stop 属性,防止在点击子菜单或空白部分触发父菜单点击事件
- 因为我的菜单有自己的选中样式所以在class上有一些三元判断,具体可以根据自己需求定义
<template>
<div class="menu" @click.stop>
<div v-for="(item, index) in menuList" :key="index" @click.stop :class="menu-item" @click="chooseMenu(index, item)">
<span :class="item.checkIndex == index ? 'name choose-item' : 'name'">{{
item.name
}}</span>
<span :class="item.checkIndex == index ? 'index choose-item' : 'index'">
{{ index + 1 }}
</span>
<Menu class="menu-children" :menuList="item.childrens" @back="back(index, $event)"></Menu>
</div>
</div>
</template>
<script>
export default {
name: "Menu",
props: {
menuList: Array,
},
methods: {
/**
* @author: yx
* @method: 选择菜单,返回菜单信息以及列下标
* @Date: 2020-09-17 10:40:18
*/
chooseMenu(index, item) {
let child = {
index: [index],
item,
};
this.$emit("back", child);
},
/**
* @author: yx
* @method: 向上次依次返回选择的菜单信息以及列下标
* @Date: 2020-09-17 10:40:27
*/
back(index, event) {
event.index.push(index);
this.$emit("back", event);
},
},
};
</script>
组件调用
注意点:
- 因为每次选择样式都需要变化,但是更改了 menList 的值之后递归组件并不能第一时间更新dom,所以在这里我定义了一个 refresh,通过 refresh 来刷新组件
<template>
<div class="home">
<Menu v-if="refresh" :menuList="menuList" @back="back($event)"></Menu>
</div>
</template>
<script>
import Menu from "../components/menu";
export default {
name: "Home",
data() {
return {
refresh: true,
menuList: [{
id: 1,
name: "测试",
checkIndex: 0,
isFirst: true,
childrens: [{
id: 2,
name: "测试1级1",
checkIndex: 0,
childrens: [{
id: 6,
name: "测试2级1",
checkIndex: 2,
childrens: [],
},
{
id: 7,
checkIndex: 2,
name: "测试2级2",
childrens: [],
}],
}],
}],
nowIndex: 0,
columnIndex: [], // 列下标
};
},
methods:{
back(item) {}
}
components: {
Menu,
}
};
</script>