el-menu遞歸實(shí)現(xiàn)多級(jí)菜單組件的示例
1. 效果:
2. 實(shí)現(xiàn):
創(chuàng)建外層菜單AsideMenu.vue
組件和子菜單項(xiàng)AsideSubMenu.vue
組件,在AsideSubMenu
中進(jìn)行遞歸操作。
AsideMenu.vue文件內(nèi)容如下:
<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; // 此處添加判斷的原因見(jiàn)說(shuō)明 if (meta.matchPath) { return meta.matchPath; } else { return path; } }, // 設(shè)置默認(rèn)展開(kāi)菜單項(xiàng) openedsArr() { // const arr = this.menuData.map((item) => { // return item.title; // }); // return arr; return []; }, }, }; </script>
判斷高亮狀態(tài)的activeMenu方法中的判斷matchPath屬性可以讓多個(gè)路由不同的頁(yè)面匹配同一個(gè)菜單高亮狀態(tài),因?yàn)椴藛胃吡翣顟B(tài)是根據(jù)路由地址匹配的。如果兩個(gè)不同的路由頁(yè)面想公用同一個(gè)菜單高亮狀態(tài)(如詳情頁(yè)面和列表頁(yè))就可以使用該方法實(shí)現(xiàn)。在router文件里設(shè)置meta對(duì)象,添加matchPath屬性設(shè)置為想要共用的高亮狀態(tài)的頁(yè)面的路由地址。(有點(diǎn)繞??)
樣式根據(jù)需求修改,示例中的樣式如下(此處包含深淺兩種主題的菜單樣式):
<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; } /* 內(nèi)層高亮 */ .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文件內(nèi)容如下:
<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>
判斷如果有子菜單則進(jìn)行遍歷操作。同時(shí)此處根據(jù)是否有icon給el-submenu
動(dòng)態(tài)添加了一個(gè)類名:class="item.icon ? '' : 'noIcon'"
,這么做是由于高亮狀態(tài)下的.el-submenu添加了圓角效果,在存在多層子菜單嵌套的情況下如果不清除圓角效果則會(huì)出現(xiàn)問(wèn)題(見(jiàn)下圖)。這個(gè)狀態(tài)下不好用選擇器選中需要操作的元素,因此根據(jù)是否有icon這個(gè)區(qū)別進(jìn)行了區(qū)分。如果是整個(gè)菜單都沒(méi)有icon的情況的話,那暫時(shí)還沒(méi)想好應(yīng)對(duì)策略。??
<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>
3. 使用組件:
- 添加路由配置;
- 引入并掛載組件;
- 傳入菜單數(shù)據(jù);
代碼如下:
<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"), } ] }
到此這篇關(guān)于el-menu遞歸實(shí)現(xiàn)多級(jí)菜單組件的示例的文章就介紹到這了,更多相關(guān)el-menu多級(jí)菜單組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Element?ui中menu組件(el-menu/el-menu-item/el-submenu/template)層級(jí)結(jié)構(gòu)與用法示例
- Vue?el-menu?左側(cè)菜單導(dǎo)航功能的實(shí)現(xiàn)
- el-menu實(shí)現(xiàn)橫向溢出截取的示例代碼
- vue+el-menu實(shí)現(xiàn)菜單欄無(wú)限多層級(jí)分類
- element 中 el-menu 組件的無(wú)限極循環(huán)思路代碼詳解
- 使用element-ui的el-menu導(dǎo)航選中后刷新頁(yè)面保持當(dāng)前選中狀態(tài)
- vue2+el-menu實(shí)現(xiàn)路由跳轉(zhuǎn)及當(dāng)前項(xiàng)的設(shè)置方法實(shí)例
相關(guān)文章
VUE 無(wú)限層級(jí)樹(shù)形數(shù)據(jù)結(jié)構(gòu)顯示的實(shí)現(xiàn)
在做項(xiàng)目中,會(huì)遇到一些樹(shù)形的數(shù)據(jù)結(jié)構(gòu),常用在左側(cè)菜單導(dǎo)航,本文就介紹一下如何實(shí)現(xiàn),感興趣的可以了解一下2021-07-07關(guān)于vue中@click.native.prevent的說(shuō)明
這篇文章主要介紹了關(guān)于vue中@click.native.prevent的說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03vue中的雙向數(shù)據(jù)綁定原理與常見(jiàn)操作技巧詳解
這篇文章主要介紹了vue中的雙向數(shù)據(jù)綁定原理與常見(jiàn)操作技巧,結(jié)合實(shí)例形式詳細(xì)分析了vue中雙向數(shù)據(jù)綁定的概念、原理、常見(jiàn)操作技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-03-03vue前臺(tái)顯示500和405錯(cuò)誤的解決(springboot為后臺(tái))
這篇文章主要介紹了vue前臺(tái)顯示500和405錯(cuò)誤的解決(springboot為后臺(tái)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07