vue通过递归组件的方法实现多级菜单

832 阅读1分钟

之前有被面试问道,问我怎么实现多级菜单,我随口就来:v-if,v-else .当然这也是可以实现的方法,只不过感觉不怎么“高级”,哈哈,在网上看了很多递归的例子,于是手痒也写了下。

先来分析:递归组件,利用插槽。总共需要四个组件: MultiMenu.vue组件先判断是否有子级菜单:没有子级菜单的单独写个组件MenuItem.vue ,有子级菜单的写个组件ReSubMenu.vue ,只不过有子级菜单的得单独写一个组件SubMenu.vue,让父级和子级对应不同的插槽来渲染。

上效果图:

A1CWQXBT_Y341{}$H@_V%D7.png

上代码:

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>

复制粘贴后打开会有标红线的地方,但不影响使用,有知道怎么改进的话,欢迎指教交流。

$YXSH2L743~83}2H7EMXJ9J.png