今天小编给大家分享一下怎么使用el-menu递归实现多级菜单组件的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
创建外层菜单AsideMenu.vue
组件和子菜单项AsideSubMenu.vue
组件,在AsideSubMenu
中进行递归操作。
AsideMenu.vue文件内容如下:
<template> <aside class="wrap"> <el-menu :default-active="activeMenu" router :class="'menu-left'" :default-openeds="openedsArr" text-color="#fff" > <AsideSubMenu :menuData="menuData"></AsideSubMenu> </el-menu> </aside> </template> <script> import AsideSubMenu from "./AsideSubMenu.vue"; export default { name: "AsideMenu", components: { AsideSubMenu, }, props: { menuData: { type: Array, }, }, computed: { activeMenu() { const route = this.$route; const { meta, path } = route; // 此处添加判断的原因见说明 if (meta.matchPath) { return meta.matchPath; } else { return path; } }, // 设置默认展开菜单项 openedsArr() { // const arr = this.menuData.map((item) => { // return item.title; // }); // return arr; return []; }, }, }; </script>
判断高亮状态的activeMenu方法中的判断matchPath属性可以让多个路由不同的页面匹配同一个菜单高亮状态,因为菜单高亮状态是根据路由地址匹配的。如果两个不同的路由页面想公用同一个菜单高亮状态(如详情页面和列表页)就可以使用该方法实现。在router文件里设置meta对象,添加matchPath属性设置为想要共用的高亮状态的页面的路由地址。(有点绕????)
样式根据需求修改,示例中的样式如下(此处包含深浅两种主题的菜单样式):
<style scoped> aside { height: 100%; text-align: center; } .el-menu { padding: 16px; box-sizing: border-box; } /* ---------- 深色 ---------- */ .menu-left, .menu-left /deep/ .el-menu { min-height: 100%; background-color: #222653; } .menu-left .icon { width: 20px; margin-right: 9px; } .menu-left /deep/.el-submenu__title, .menu-left /deep/.el-menu-item { box-sizing: border-box; font-size: 14px; font-family: PingFangSC-Regular, PingFang SC; text-align: left; color: #b3c0e7 !important; background-color: #222653 !important; } .menu-left /deep/.el-submenu__title i { color: #b3c0e7 !important; } .menu-left /deep/.el-submenu__title { height: 54px; line-height: 54px; /* padding-left: 36px !important; */ } .menu-left /deep/ .el-menu-item { height: 52px; line-height: 52px; } .menu-left /deep/.el-submenu .el-menu-item { padding-left: 45px !important; } /* 外层高亮 */ .menu-left /deep/.el-submenu.is-active, .menu-left /deep/.el-submenu.is-active .el-menu-item, .menu-left /deep/.el-submenu.is-active .el-submenu__title, .menu-left /deep/.el-menu-item.is-active { background-color: #4880ff !important; } .menu-left /deep/.el-submenu.is-active { border-radius: 10px; overflow: hidden; } .menu-left /deep/ .el-menu-item.is-active { border-radius: 10px; } .menu-left /deep/ .el-menu--inline .el-menu-item.is-active, .menu-left /deep/ .el-submenu.noIcon { border-radius: 0; } .menu-left /deep/ .el-submenu.noIcon .el-submenu__title { padding-left: 45px !important; } .menu-left /deep/ .el-submenu.noIcon .el-menu-item { padding-left: 58px !important; } .menu-left /deep/.el-submenu.is-active > .el-submenu__title, .menu-left /deep/.el-submenu.is-active > .el-submenu__title i { color: #ffffff !important; } /* 内层高亮 */ .menu-left /deep/.el-menu-item:focus, .menu-left /deep/.el-menu-item:hover, .menu-left /deep/.el-menu-item.is-active { color: #ffffff !important; font-weight: 500; } .menu-left /deep/.el-menu-item.is-disabled { padding-left: 45px !important; color: #ffffff !important; } /* ---------- 浅色 ---------- */ .menu-left-light { height: 100%; background-color: #f8f8f8; } .menu-left-light .icon { width: 20px; margin-right: 9px; } .menu-left-light /deep/.el-submenu__title, .menu-left-light /deep/.el-menu-item { box-sizing: border-box; font-size: 16px; font-family: PingFangSC-Regular, PingFang SC; text-align: left; color: #333333; } .menu-left-light /deep/.el-submenu__title { height: 52px; line-height: 52px; padding-left: 56px !important; } .menu-left-light /deep/.el-submenu__title:hover { background-color: #ffffff !important; } .menu-left-light /deep/.el-submenu__icon-arrow { right: 85px; } .menu-left-light /deep/.el-submenu__title i { color: #333333; } .menu-left-light /deep/.el-menu-item { height: 40px; line-height: 40px; padding-left: 82px !important; border-left: 4px solid #ffffff; } .menu-left-light /deep/.el-menu-item:focus, .menu-left-light /deep/.el-menu-item:hover, .menu-left-light /deep/.el-menu-item.is-active { background: rgba(31, 65, 219, 0.1) !important; color: #1f41db !important; border-color: #1f41db; } .menu-left-light /deep/.el-menu-item.is-disabled { background: #ffffff !important; color: #333333 !important; } </style>
AsideMenu.vue文件内容如下:
<template> <div> <template v-for="item in menuData"> <el-submenu :key="item.path" v-if="item.children && item.children.length > 0" :index="item.path" :class="item.icon ? '' : 'noIcon'" > <template slot="title"> <img class="icon mr-r-10" :src=" curRoute.indexOf(item.path) != -1 ? item.iconActive : item.icon " /> <span>{{ item.title }}</span> </template> <AsideSubMenu :menuData="item.children"></AsideSubMenu> </el-submenu> <el-menu-item :key="item.id" v-else :index="item.path" :disabled="item.disabled" > <template slot="title"> <img class="icon mr-r-10" :src=" curRoute.indexOf(item.path) != -1 ? item.iconActive : item.icon " /> <span>{{ item.title }}</span> </template> </el-menu-item> </template> </div> </template>
判断如果有子菜单则进行遍历操作。同时此处根据是否有icon给el-submenu
动态添加了一个类名:class="item.icon ? '' : 'noIcon'"
,这么做是由于高亮状态下的.el-submenu添加了圆角效果,在存在多层子菜单嵌套的情况下如果不清除圆角效果则会出现问题(见下图)。这个状态下不好用选择器选中需要操作的元素,因此根据是否有icon这个区别进行了区分。如果是整个菜单都没有icon的情况的话,那暂时还没想好应对策略。????
<script> import AsideSubMenu from "./AsideSubMenu.vue"; export default { name: "AsideSubMenu", components: { AsideSubMenu, }, props: { menuData: { type: Array, default: () => { return []; }, }, }, computed: { curRoute() { return this.$route.path; }, }, }; </script>
添加路由配置;
引入并挂载组件;
传入菜单数据;
代码如下:
<template> <el-container class="container"> <el-aside width="320px"> <AsideMenu :menuData="menuData"></AsideMenu> </el-aside> <el-main> <keep-alive :exclude="[]"> <router-view></router-view> </keep-alive> </el-main> </el-container> </template> <script> import AsideMenu from '@/components/AsideMenu.vue'; export default { name: 'MenuTest', components: { AsideMenu }, data() { return { menuData: [ { title: '菜单一', path: '/menutest/menu1', icon: require('@/assets/icons/apply.svg'), iconActive: require('@/assets/icons/apply_active.svg'), children: [ { title: '子菜单一', path: '/menutest/menu1/menu1-1', // disabled: true, }, { title: '子菜单二', path: '/menutest/menu1/menu1-2' } ] }, { title: '菜单二', path: '/menutest/menu2', icon: require('@/assets/icons/apply.svg'), iconActive: require('@/assets/icons/apply_active.svg'), children: [ { title: '子菜单一', path: '/menutest/menu2/menu2-1' }, { title: '子菜单二', path: '/menutest/menu2/menu2-2', children: [ { title: '孙子菜单一', path: '/menutest/menu2/menu2-2/menu2-1-1' }, { title: '孙子菜单二', path: '/menutest/menu2/menu2-2/menu2-2-2' } ] }, { title: '子菜单三', path: '/menutest/menu2/menu2-3' } ] }, { title: '菜单三', path: '/menutest/menu3', icon: require('@/assets/icons/apply.svg'), iconActive: require('@/assets/icons/apply_active.svg'), } ] }; } }; </script> <style scoped> .container { min-height: 800px; } .el-main { padding: 32px 40px; box-sizing: border-box; background: #f5f5fa; overflow-y: auto; } </style>
示例中的路由配置如下:
{ path: "/menutest", name: "Menu", component: () => import("../views/MenuTest.vue"), redirect: "/menutest/menu1", children: [{ path: '/menutest/menu1', component: () => import("../views/menuPages/menu1.vue"), children: [{ path: '/menutest/menu1/menu1-1', component: () => import("../views/menuPages/menu1-1.vue"), }, { path: '/menutest/menu1/menu1-2', component: () => import("../views/menuPages/menu1-2.vue"), } ] }, { path: '/menutest/menu2', component: () => import("../views/menuPages/menu2.vue"), children: [{ path: '/menutest/menu2/menu2-1', component: () => import("../views/menuPages/menu2-1.vue"), }, { path: '/menutest/menu2/menu2-2', component: () => import("../views/menuPages/menu2-2.vue"), children: [{ path: '/menutest/menu2/menu2-2/menu2-1-1', component: () => import("../views/menuPages/menu2-1-1.vue"), }, { path: '/menutest/menu2/menu2-2/menu2-2-2', component: () => import("../views/menuPages/menu2-1-2.vue"), } ] }, { path: '/menutest/menu2/menu2-3', component: () => import("../views/menuPages/menu2-3.vue"), } ] }, { path: '/menutest/menu3', component: () => import("../views/menuPages/menu3.vue"), } ] }
以上就是“怎么使用el-menu递归实现多级菜单组件”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。