之前有被面试问道,问我怎么实现多级菜单,我随口就来:v-if,v-else .当然这也是可以实现的方法,只不过感觉不怎么“高级”,哈哈,在网上看了很多递归的例子,于是手痒也写了下。
先来分析:递归组件,利用插槽。总共需要四个组件: MultiMenu.vue组件先判断是否有子级菜单:没有子级菜单的单独写个组件MenuItem.vue ,有子级菜单的写个组件ReSubMenu.vue ,只不过有子级菜单的得单独写一个组件SubMenu.vue,让父级和子级对应不同的插槽来渲染。
上效果图:
上代码:
MultiMenu.vue 组件 : 注意: template上面不能有key, 两种办法1.换成别的标签。2.将key放在别的标签上面
<template>
<div>
<div>这是一个多级菜单</div>
<!-- 注意: template上面不能有key, 两种办法1.换成别的标签。2.将key放在别的标签上面-->
<template v-for="menu in Mydata">
<!-- 第一步 根据不同的条件渲染出不同的内容-->
<MenuItem :key="menu.id" v-if="!menu.children">{{menu.title}}</MenuItem>
<ReSubMenu :key="menu.id" v-else :data="menu"></ReSubMenu>
</template>
</div>
</template>
<script>
import MenuItem from '../views/MenuItem.vue'
import ReSubMenu from '../views/ReSubMenu.vue'
export default {
components:{
MenuItem,
ReSubMenu
},
data() {
return {
input: '',
Mydata:[
{
title:'菜单1',
id:1,
children:[
{
title:'菜单1-1',
id:1-1,
children:[
{title:'菜单1-1-1',id:1-1-1,},
{title:'菜单1-1-2',id:1-1-2},
{title:'菜单1-1-3',id:1-1-3,children:[
{title:'菜单1-1-3-1',id:1-1-3-1}
]}
]
},
{title:'菜单1-2'},
{title:'菜单1-3'}
]
},
{title:'菜单2',id:2},
{title:'菜单3', id:3,
children:[
{title:'菜单3-1',id:3-1,},
{title:'菜单3-2',id:3-2,}
]}
]
}
},
}
</script>
<style scoped>
</style>
MenuItem.vue 组件 : 就一个插槽,没有子级菜单的使用
<template>
<div>
<div class="title"><slot></slot></div>
</div>
</template>
<script>
export default {
}
</script>
<style>
.title{
background-color: aquamarine;
margin-top: 5px;
width: 100px;
line-height: 40px;
text-align: center;
}
</style>
SubMenu.vue 组件 : 有子级菜单的使用
<template>
<div>
<div class="title" @click="change">
<slot name="title"></slot>
</div>
<div class="sub" v-show="flag">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: "SubMenu",
data(){
return {flag:false}
},
methods:{
change(){
this.flag=!this.flag
}
}
}
</script>
<style>
.sub{
padding-left:20px;
}
.title,sub{
background-color: aquamarine;
margin-top: 5px;
width: 100px;
line-height: 40px;
text-align: center;
}
</style>
ReSubMenu.vue 组件: 注意一点:看下面的注意事项
<template>
<div>
<SubMenu>
<template slot="title">
<div>{{data.title}}</div>
</template>
<template v-for="child in data.children" >
<MenuItem :key="child.id" v-if="!child.children">{{child.title}}</MenuItem>
<!-- ReSubMenu跟下面的属性name的值保持一致,相当于循环使用该组件 -->
<ReSubMenu v-else :key="child.id" :data="child"></ReSubMenu>
</template>
</SubMenu>
</div>
</template>
<script>
import SubMenu from '../views/SubMenu.vue'
import MenuItem from '../views/MenuItem.vue'
// 注意事项: 组建当中不能引进使用组件本身,否则报错,要使用,用下面的 name: "ReSubMenu" 方式。
// import ReSubMenu from '../views/ReSubMenu.vue'
export default {
name: "ReSubMenu",// 使用递归组件
props:{
data:{
type:Object,// 属性校验,为对象数据类型,并且如果没有赋值,默认给一个空对象
default:()=>({})
}
},
components:{
SubMenu,
MenuItem,
}
}
</script>
<style>
</style>
复制粘贴后打开会有标红线的地方,但不影响使用,有知道怎么改进的话,欢迎指教交流。