前端开发中,经常遇到需要与后端配置,前端动态渲染菜单的应用场景,而究其本质,就是菜单组件的应用,只是在不确定菜单级数的情况下,我们需要对组件做一个递归处理,让它能够适应大多数应用场景。
如上图所示,以Element-Plus组件库为例,对于一个递归型菜单,我们该如何进行封装呢?先假设后端接口返回的简单菜单信息如下,
[{index: "1",path: "/index",routeParams: {},meta: {title: "首页",icon: "House",}},{index: "2",path: "/funcs",routeParams: {},meta: {title: "功能中心",icon: "Menu",}},{index: "3",path: "/cases",routeParams: {},meta: {title: "项目案例",icon: "Grid",mode:"vertical",},children: [{index: "3-1",path: "",routeParams: {},meta: {title: "item one",icon: "Orange",},children:[{index: "3-1-1",path: "",routeParams: {},meta: {title: "item one-one",icon: "Orange",},}]},{index: "3-2",path: "",routeParams: {},meta: {title: "item two",icon: "Orange",}},{index: "3-3",path: "",routeParams: {},meta: {title: "item three",icon: "Orange",}}]}]
实际开发中,还可能包括组件路径、菜单项显隐等相关字段信息,此处暂不考虑,我们当前的核心需求是:如何去完成这样的一个菜单组件的封装。
对于上图所示的效果,我在此处所做的组件封装示例代码如下,
<!-- 多级菜单组件抽取 -->
<template><el-menu :default-active="activeIndex" :class="customMenuClass" background-color="transparent" text-color="#fff"active-text-color="#ffef40" :mode="mode" @select="handleSelect" :ellipsis="false"><template v-for="(item) in items"><template v-if="item.children"><el-sub-menu :index="item.index" popper-class="el-sub-menu-popper-class"><template #title><router-link :to="item.path"><el-icon><component :is="item.meta.icon" :size="24"></component></el-icon><span>{{ item.meta.title }}</span></router-link></template><menu-list :items="item.children" :mode="item.meta.mode"></menu-list></el-sub-menu></template><template v-else><el-menu-item :index="item.index" :key="item.path"><router-link :to="item.path"><el-icon><component :is="item.meta.icon" :size="24"></component></el-icon><span>{{ item.meta.title }}</span></router-link></el-menu-item></template></template></el-menu>
</template>
<script>
export default {name: "menu-list",props: {customMenuClass: {type: String,required: false,default: "el-menu-class",},mode: {type: String,default: "horizontal",},items: {type: Array,required: true,},activeIndex: {type: String,required: false,default: "",}},data() {return {}},methods: {handleSelect(key, keyPath, menuItem) {this.$emit("select",{key, keyPath, menuItem})}}}
</script>
<style lang="scss" scoped>
.el-menu-class {.el-menu-item:not(.is-disabled):hover {background-color: rgba(127, 255, 212, .3);}
}
</style>
<style lang="scss">
.el-sub-menu-popper-class {background-color: $base-background-color !important;
}
</style>
使用示例如下,
//menuList变量对应的就是文章开头处给出的示例数据<MenuList :items="menuList" active-index="1" mode="horizontal"/>
最终,我们就能完成这样的一个递归型菜单组件了,但是对于菜单的样式,可以根据实际需要进行定制。