Vue結合路由配置遞迴實現選單欄功能
前言
在日常開發中,專案中的選單欄都是已經實現好了的。如果需要新增新的選單,只需要在路由配置
中新增一條路由,就可以實現選單的新增。
相信大家和我一樣,有時候會躍躍欲試自己去實現一個選單欄。那今天我就將自己實現的選單欄的整個思路和程式碼分享給大家。
本篇文章重在總結和分享選單欄的一個遞迴實現方式
,程式碼的優化
、選單許可權
等不在本篇文章範圍之內,在文中的相關部分也會做一些提示,有個別不推薦的寫法希望大家不要參考哦。
同時可能會存在一些細節的功能沒有處理或者沒有提及到,忘知曉。
最終的效果
本次實現的這個選單欄包含有一級選單
、二級選單
和三級選單
這三種類型,基本上已經可以覆蓋專案中不同的選單需求。
後面會一步一步從易到難去實現這個選單。
簡單實現
我們都知道到element
提供了 NavMenu
導航選單元件,因此我們直接按照文件將這個選單欄做一個簡單的實現。
基本的佈局架構圖如下:
選單首頁-menuIndex
首先要實現的是選單首頁
這個元件,根據前面的佈局架構圖並且參考官方文件,實現起來非常簡單。
<!-- src/menu/menuIndex.vue --> <template> <div id="menu-index"> <el-container> <el-header> <TopMenu :logoPath="logoPath" :name="name"></TopMenu> </el-header> <el-container id="left-container"> <el-aside width="200px"> <LeftMenu></LeftMenu> </el-aside> <el-main> <router-view/> </el-main> </el-container> </el-container> </div> </template> <script> import LeftMenu from './leftMenu'; import TopMenu from './topMenu'; export default { name: 'MenuIndex',components: {LeftMenu,TopMenu},data() { return { logoPath: require("../../assets/images/logo1.png"),name: '員工管理系統' } } } </script> <style lang="scss"> #menu-index{ .el-header{ padding: 0px; } } </style>
頂部選單欄-topMenu
頂部選單欄主要就是一個logo
和產品名稱
。
邏輯程式碼也很簡單,我直接將程式碼貼上。
<!-- src/menu/leftMenu.vue --> <template> <div id="top-menu"> <img class="logo" :src="logoPath" /> <p class="name">{{name}}</p> </div> </template> <script> export default { name: 'topMenu',props: ['logoPath','name'] } </script> <style lang="scss" scoped> $topMenuWidth: 80px; $logoWidth: 50px; $bg-color: #409EFF; $name-color: #fff; $name-size: 18px; #top-menu{ height: $topMenuWidth; text-align: left; background-color: $bg-color; padding: 20px 20px 0px 20px; .logo { width: $logoWidth; display: inline-block; } .name{ display: inline-block; vertical-align: bottom; color: $name-color; font-size: $name-size; } } </style>
這段程式碼中包含了父元件
傳遞給子元件
的兩個資料。
props: ['logoPath','name']
這個是父元件menuIndex
傳遞給子元件topMenu
的兩個資料,分別是logo圖示的路徑
和產品名稱
。
完成後的介面效果如下。
左側選單欄-leftMenu
首先按照官方文件實現一個簡單的選單欄。
<!-- src/menu/leftMenu.vue --> <template> <div id="left-menu"> <el-menu :default-active="$route.path" class="el-menu-vertical-demo" :collapse="false"> <el-menu-item index="1"> <i class="el-icon-s-home"></i> <span slot="title">首頁</span> </el-menu-item> <el-submenu index="2"> <template slot="title"> <i class="el-icon-user-solid"></i> <span slot="title">員工管理</span> </template> <el-menu-item index="2-1">員工統計</el-menu-item> <el-menu-item index="2-2">員工管理</el-menu-item> </el-submenu> <el-submenu index="3"> <template slot="title"> <i class="el-icon-s-claim"></i> <span slot="title">考勤管理</span> </template> <el-menu-item index="3-1">考勤統計</el-menu-item> <el-menu-item index="3-2">考勤列表</el-menu-item> <el-menu-item index="3-2">異常管理</el-menu-item> </el-submenu> <el-submenu index="4"> <template slot="title"> <i class="el-icon-location"></i> <span slot="title">工時管理</span> </template> <el-menu-item index="4-1">工時統計</el-menu-item> <el-submenu index="4-2"> <template slot="title">工時列表</template> <el-menu-item index="4-2-1">選項一</el-menu-item> <el-menu-item index="4-2-2">選項二</el-menu-item> </el-submenu> </el-submenu> </el-menu> </div> </template> <script> export default { name: 'LeftMenu' } </script> <style lang="scss"> // 使左邊的選單外層的元素高度充滿螢幕 #left-container{ position: absolute; top: 100px; bottom: 0px; // 使選單高度充滿螢幕 #left-menu,.el-menu-vertical-demo{ height: 100%; } } </style>
注意選單的樣式程式碼,設定了絕對定位
,並且設定top
、bottom
使選單高度撐滿螢幕。
此時在看下介面效果。
基本上算是實現了一個簡單的選單佈局。
不過在實際專案在設計的時候,選單欄的內容有可能來自後端給我們返回的資料,其中包含選單名稱
、選單圖示
以及選單之間的層級關係
。
總而言之,我們的選單是動態生成的,而不是像前面那種固定的寫法。因此下面我將實現一個動態生成的選單,選單的資料來源於我們的路由配置
。
結合路由配置實現動態選單
路由配置
首先,我將專案的路由配置程式碼貼出來。
import Vue from 'vue'; import Router from "vue-router"; // 選單 import MenuIndex from '@/components/menu/menuIndex.vue'; // 首頁 import Index from '@/components/homePage/index.vue'; // 人員統計 import EmployeeStatistics from '@/components/employeeManage/employeeStatistics.vue'; import EmployeeManage from '@/components/employeeManage/employeeManage.vue' // 考勤 // 考勤統計 import AttendStatistics from '@/components/attendManage/attendStatistics'; // 考勤列表 import AttendList from '@/components/attendManage/attendList.vue'; // 異常管理 import ExceptManage from '@/components/attendManage/exceptManage.vue'; // 工時 // 工時統計 import TimeStatistics from '@/components/timeManage/timeStatistics.vue'; // 工時列表 import TimeList from '@/components/timeManage/timeList.vue'; Vue.use(Router) let routes = [ // 首頁(儀表盤、快速入口) { path: '/index',name: 'index',component: MenuIndex,redirect: '/index',meta: { title: '首頁',// 選單標題 icon: 'el-icon-s-home',// 圖示 hasSubMenu: false,// 是否包含子選單,false 沒有子選單;true 有子選單 },children:[ { path: '/index',component: Index } ] },// 員工管理 { path: '/employee',name: 'employee',redirect: '/employee/employeeStatistics',meta: { title: '員工管理',// 選單標題 icon: 'el-icon-user-solid',// 圖示 hasSubMenu: true,// 是否包含子選單 },children: [ // 員工統計 { path: 'employeeStatistics',name: 'employeeStatistics',meta: { title: '員工統計',// 選單標題,hasSubMenu: false // 是否包含子選單 },component: EmployeeStatistics,},// 員工管理(增刪改查) { path: 'employeeManage',name: 'employeeManage',meta: { title: '員工管理',// 選單標題 hasSubMenu: false // 是否包含子選單 },component: EmployeeManage } ] },// 考勤管理 { path: '/attendManage',name: 'attendManage',redirect: '/attendManage/attendStatistics',meta: { title: '考勤管理',// 選單標題 icon: 'el-icon-s-claim',// 是否包含子節點,false 沒有子選單;true 有子選單 },children:[ // 考勤統計 { path: 'attendStatistics',name: 'attendStatistics',meta: { title: '考勤統計',// 選單標題 hasSubMenu: false // 是否包含子選單 },component: AttendStatistics,// 考勤列表 { path: 'attendList',name: 'attendList',meta: { title: '考勤列表',// 選單標題 hasSubMenu: false // 是否包含子選單 },component: AttendList,// 異常管理 { path: 'exceptManage',name: 'exceptManage',meta: { title: '異常管理',component: ExceptManage,} ] },// 工時管理 { path: '/timeManage',name: 'timeManage',redirect: '/timeManage/timeStatistics',meta: { title: '工時管理',// 選單標題 icon: 'el-icon-message-solid',// 是否包含子選單,false 沒有子選單;true 有子選單 },children: [ // 工時統計 { path: 'timeStatistics',name: 'timeStatistics',meta: { title: '工時統計',// 選單標題 hasSubMenu: false // 是否包含子選單 },component: TimeStatistics },// 工時列表 { path: 'timeList',name: 'timeList',component: TimeList,meta: { title: '工時列表',// 選單標題 hasSubMenu: true // 是否包含子選單 },children: [ { path: 'options1',meta: { title: '選項一',// 選單標題 hasSubMenu: false // 是否包含子選單 },{ path: 'options2',meta: { title: '選項二',] } ] },]; export default new Router({ routes })
在這段程式碼的最開始部分,我們引入了需要使用的元件,接著就對路由進行了配置。
此處使用了直接引入元件的方式,專案開發中不推薦
這種寫法,應該使用懶載入
的方式
路由配置除了最基礎的path
、component
以及children
之外,還配置了一個meta
資料項。
meta: { title: '工時管理',// 選單標題 icon: 'el-icon-message-solid',// 圖示 hasSubMenu: true,// 是否包含子節點,false 沒有子選單;true 有子選單 }
meta
資料包含的配置有選單標題
(title
)、圖示的類名
(icon
)和是否包含子節點
(hasSubMenu
)。
根據title
、icon
這兩個配置項,可以展示當前選單的標題
和圖示
。
hasSubMenu
表示當前的選單項是否有子選單,如果當前選單包含有子選單(hasSubMenu
為true
),那當前選單對應的標籤元素就是el-submenu
;否則當前選單對應的選單標籤元素就是el-menu-item
。
是否包含子選單是一個非常關鍵的邏輯,我在實現的時候是直接將其配置到了meta.hasSubMenu
這個引數裡面。
根據路由實現多級選單
路由配置完成後,我們就需要根據路由實現選單了。
獲取路由配置
既然要根據路由配置實現多級選單,那第一步就需要獲取我們的路由資料。這裡我使用簡單粗暴的方式去獲取路由配置資料:this.$router.options.routes
。
這種方式也不太適用日常的專案開發,因為無法在獲取的時候對路由做進一步的處理,比如許可權控制
。
我們在元件載入時列印一下這個資料。
// 程式碼位置:src/menu/leftMenu.vue mounted(){ console.log(this.$router.options.routes); }
列印結果如下。
可以看到這個資料就是我們在router.js
中配置的路由資料。
為了方便使用,我將這個資料定義到計算屬性中。
// 程式碼位置:src/menu/leftMenu.vue computed: { routesInfo: function(){ return this.$router.options.routes; } }
一級選單
首先我們來實現一級選單
。
主要的邏輯就是迴圈路由資料routesInfo
,在迴圈的時候判斷當前路由route
是否包含子選單,如果包含則當前選單使用el-submenu
實現,否則當前選單使用el-menu-item
實現。
<!-- src/menu/leftMenu.vue --> <el-menu :default-active="$route.path" class="el-menu-vertical-demo" :collapse="false"> <!-- 一級選單 --> <!-- 迴圈路由資料 --> <!-- 判斷當前路由route是否包含子選單 --> <el-submenu v-for="route in routesInfo" v-if="route.meta.hasSubMenu" :index="route.path"> <template slot="title"> <i :class="route.meta.icon"></i> <span slot="title">{{route.meta.title}}</span> </template> </el-submenu> <el-menu-item :index="route.path" v-else> <i :class="route.meta.icon"></i> <span slot="title">{{route.meta.title}}</span> </el-menu-item> </el-menu>
結果:
可以看到,我們第一級選單已經生成了,員工管理
、考勤管理
、工時管理
這三個選單是有子選單的,所以會有一個下拉按鈕。
不過目前點開是沒有任何內容的,接下來我們就來實現這三個選單下的二級選單
。
二級選單
二級選單
的實現和一級選單
的邏輯是相同的:迴圈子路由route.children
,在迴圈的時候判斷子路由childRoute
是否包含子選單,如果包含則當前選單使用el-submenu
實現,否則當前選單使用el-menu-item
實現。
那話不多說,直接上程式碼。
<!-- src/menu/leftMenu.vue --> <el-menu :default-active="$route.path" class="el-menu-vertical-demo" :collapse="false"> <!-- 一級選單 --> <!-- 迴圈路由資料 --> <!-- 判斷當前路由route是否包含子選單 --> <el-submenu v-for="route in routesInfo" v-if="route.meta.hasSubMenu" :index="route.path"> <template slot="title"> <i :class="route.meta.icon"></i> <span slot="title">{{route.meta.title}}</span> </template> <!-- 二級選單 --> <!-- 迴圈子路由`route.children` --> <!-- 迴圈的時候判斷子路由`childRoute`是否包含子選單 --> <el-submenu v-for="childRoute in route.children" v-if="childRoute.meta.hasSubMenu" :index="childRoute.path"> <template slot="title"> <i :class="childRoute.meta.icon"></i> <span slot="title">{{childRoute.meta.title}}</span> </template> </el-submenu> <el-menu-item :index="childRoute.path" v-else> <i :class="childRoute.meta.icon"></i> <span slot="title">{{childRoute.meta.title}}</span> </el-menu-item> </el-submenu> <el-menu-item :index="route.path" v-else> <i :class="route.meta.icon"></i> <span slot="title">{{route.meta.title}}</span> </el-menu-item> </el-menu>
結果如下:
可以看到二級選單
成功實現。
三級選單
三級選單
就不用多說了,和一級
、二級
邏輯相同,這裡還是直接上程式碼。
<!-- src/menu/leftMenu.vue --> <el-menu :default-active="$route.path" class="el-menu-vertical-demo" :collapse="false"> <!-- 一級選單 --> <!-- 迴圈路由資料 --> <!-- 判斷當前路由route是否包含子選單 --> <el-submenu v-for="route in routesInfo" v-if="route.meta.hasSubMenu" :index="route.path"> <template slot="title"> <i :class="route.meta.icon"></i> <span slot="title">{{route.meta.title}}</span> </template> <!-- 二級選單 --> <!-- 迴圈子路由`route.children` --> <!-- 迴圈的時候判斷子路由`childRoute`是否包含子選單 --> <el-submenu v-for="childRoute in route.children" v-if="childRoute.meta.hasSubMenu" :index="childRoute.path"> <template slot="title"> <i :class="childRoute.meta.icon"></i> <span slot="title">{{childRoute.meta.title}}</span> </template> <!-- 三級選單 --> <!-- 迴圈子路由`childRoute.children` --> <!-- 迴圈的時候判斷子路由`child`是否包含子選單 --> <el-submenu v-for="child in childRoute.children" v-if="child.meta.hasSubMenu" :index="child.path"> <template slot="title"> <i :class="child.meta.icon"></i> <span slot="title">{{child.meta.title}}</span> </template> </el-submenu> <el-menu-item :index="child.path" v-else> <i :class="child.meta.icon"></i> <span slot="title">{{child.meta.title}}</span> </el-menu-item> </el-submenu> <el-menu-item :index="childRoute.path" v-else> <i :class="childRoute.meta.icon"></i> <span slot="title">{{childRoute.meta.title}}</span> </el-menu-item> </el-submenu> <el-menu-item :index="route.path" v-else> <i :class="route.meta.icon"></i> <span slot="title">{{route.meta.title}}</span> </el-menu-item> </el-menu>
可以看到工時列表
下的三級選單
已經顯示了。
總結
此時我們已經結合路由配置
實現了這個動態的選單。
不過這樣的程式碼在邏輯上相關於三層巢狀
的for
迴圈,對應的是我們有三層的選單。
假如我們有四層
、五層
甚至更多層的選單時,那我們還得在巢狀更多層for
迴圈。很顯然這樣的方式暴露了前面多層for
迴圈的缺陷,所以我們就需要對這樣的寫法進行一個改進。
遞迴實現動態選單
前面我們一直在說一級
、二級
、三級
選單的實現邏輯都是相同的:迴圈子路由,在迴圈的時候判斷子路由是否包含子選單,如果包含則當前選單使用el-submenu
實現,否則當前選單使用el-menu-item
實現。那這樣的邏輯最適合的就是使用遞迴
去實現。
所以我們需要將這部分共同的邏輯抽離出來作為一個獨立的元件,然後遞迴的呼叫這個元件。
邏輯拆分
<!-- src/menu/menuItem.vue --> <template> <div> <el-submenu v-for="child in route" v-if="child.meta.hasSubMenu" :index="child.path"> <template slot="title"> <i :class="child.meta.icon"></i> <span slot="title">{{child.meta.title}}</span> </template> </el-submenu> <el-menu-item :index="child.path" v-else> <i :class="child.meta.icon"></i> <span slot="title">{{child.meta.title}}</span> </el-menu-item> </div> </template> <script> export default { name: 'MenuItem',props: ['route'] } </script>
需要注意的是,這次抽離出來的元件迴圈的時候直接迴圈的是route
資料,那這個route
資料是什麼呢。
我們先看一下前面三層迴圈中迴圈的資料來源分別是什麼。
為了看得更清楚,我將前面程式碼中一些不相關的內容進行了刪減。
<!-- src/menu/leftMenu.vue --> <!-- 一級選單 --> <el-submenu v-for="route in routesInfo" v-if="route.meta.hasSubMenu"> <!-- 二級選單 --> <el-submenu v-for="childRoute in route.children" v-if="childRoute.meta.hasSubMenu"> <!-- 三級選單 --> <el-submenu v-for="child in childRoute.children" v-if="child.meta.hasSubMenu"> </el-submenu> </el-submenu> </el-submenu>
從上面的程式碼可以看到:
一級選單迴圈的是`routeInfo`,即最初我們獲取的路由資料`this.$router.options.routes`,迴圈出來的每一項定義為`route`
二級選單迴圈的是`route.children`,迴圈出來的每一項定義為`childRoute`
三級選單迴圈的是`childRoute.children`,迴圈出來的每一項定義為`child`
按照這樣的邏輯,可以發現二級選單
、三級選單
迴圈的資料來源都是相同的,即前一個迴圈結果項的children
,而一級選單的資料來源於this.$router.options.routes
。
前面我們抽離出來的menuItem
元件,迴圈的是route
資料,即不管是一層選單
還是二層
、三層選單
,都是同一個資料來源,因此我們需要統一資料來源。那當然也非常好實現,我們在呼叫元件的時候,為元件傳遞不同的值即可。
程式碼實現
前面公共元件已經拆分出來了,後面的程式碼就非常好實現了。
首先是抽離出來的meunItem
元件,實現的是邏輯判斷
以及遞迴呼叫自身
。
<!-- src/menu/menuItem.vue --> <template> <div> <el-submenu v-for="child in route" v-if="child.meta.hasSubMenu" :index="child.path"> <template slot="title"> <i :class="child.meta.icon"></i> <span slot="title">{{child.meta.title}}</span> </template> <!--遞迴呼叫元件自身 --> <MenuItem :route="child.children"></MenuItem> </el-submenu> <el-menu-item :index="child.path" v-else> <i :class="child.meta.icon"></i> <span slot="title">{{child.meta.title}}</span> </el-menu-item> </div> </template> <script> export default { name: 'MenuItem',props: ['route'] } </script>
接著是leftMenu
元件,呼叫menuIndex
元件,傳遞原始的路由資料routesInfo
。
<!-- src/menu/leftMenu.vue --> <template> <div id="left-menu"> <el-menu :default-active="$route.path" class="el-menu-vertical-demo" :collapse="false"> <MenuItem :route="routesInfo"></MenuItem> </el-menu> </div> </template> <script> import MenuItem from './menuItem' export default { name: 'LeftMenu',components: { MenuItem } } </script> <style lang="scss"> // 使左邊的選單外層的元素高度充滿螢幕 #left-container{ position: absolute; top: 100px; bottom: 0px; // 使選單高度充滿螢幕 #left-menu,.el-menu-vertical-demo{ height: 100%; } } </style>
最終的結果這裡就不展示了,和我們需要實現的結果是一致的。
功能完善
到此,我們結合路由配置實現了選單欄
這個功能基本上已經完成了,不過這是一個缺乏靈魂的選單欄,因為沒有設定選單的跳轉,我們點選選單欄還無法路由跳轉到對應的元件
,所以接下來就來實現這個功能。
選單跳轉的實現方式有兩種,第一種是NavMenu
元件提供的跳轉方式。
第二種是在選單上新增router-link
實現跳轉。
那本次我選擇的是第一種方式實現跳轉,這種實現方式需要兩個步驟才能完成,第一步是啟用el-menu
上的router
;第二步是設定導航的index
屬性。
那下面就來實現這兩個步驟。
啟用el-menu上的router
<!-- src/menu/leftMenu.vue --> <!-- 省略其餘未修改程式碼--> <el-menu :default-active="$route.path" class="el-menu-vertical-demo" router :collapse="false"> <MenuItem :route="routesInfo"> </MenuItem> </el-menu>
設定導航的index屬性
首先我將每一個選單標題對應需要設定的index
屬性值列出來。
index
值對應的是每個選單在路由中配置的path
值
首頁 員工管理 員工統計 index="/employee/employeeStatistics" 員工管理 index="/employee/employeeManage" 考勤管理 考勤統計 index="/attendManage/attendStatistics" 考勤列表 index="/attendManage/attendList" 異常管理 index="/attendManage/exceptManage" 員工統計 員工統計 index="/timeManage/timeStatistics" 員工統計 index="/timeManage/timeList" 選項一 index="/timeManage/timeList/options1" 選項二 index="/timeManage/timeList/options2"
接著在回顧前面遞迴呼叫的元件,導航選單的index
設定的是child.path
,為了看清楚child.path
的值,我將其新增選單標題的右側,讓其顯示到介面上。
<!-- src/menu/menuItem.vue --> <!-- 省略其餘未修改程式碼--> <el-submenu v-for="child in route" v-if="child.meta.hasSubMenu" :index="child.path"> <template slot="title"> <i :class="child.meta.icon"></i> <span slot="title">{{child.meta.title}} | {{child.path}}</span> </template> <!--遞迴呼叫元件自身 --> <MenuItem :route="child.children"></MenuItem> </el-submenu> <el-menu-item :index="child.path" v-else> <i :class="child.meta.icon"></i> <span slot="title">{{child.meta.title}} | {{child.path}}</span> </el-menu-item>
同時將選單欄的寬度由200px
設定為400px
。
<!-- src/menu/menuIndex.vue --> <!-- 省略其餘未修改程式碼--> <el-aside width="400px"> <LeftMenu></LeftMenu> </el-aside>
然後我們看一下效果。
可以發現,child.path
的值就是當前選單在路由中配置path
值(router.js
中配置的path
值)。
那麼問題就來了,前面我們整理了每一個選單標題對應需要設定的index
屬性值,就目前來看,現在設定的index
值是不符合要求的。不過仔細觀察現在選單設定的index
值和正常值是有一點接近的,只是缺少了上一級選單的path
值,如果能將上一級選單
的path
值和當前選單的path
值進行一個拼接,就能得到正確的index
值了。
那這個思路實現的方式依然是在遞迴時將當前選單的path
作為引數傳遞給menuItem
元件。
<!-- src/menu/menuIndex.vue --> <!--遞迴呼叫元件自身 --> <MenuItem :route="child.children" :basepath="child.path"> </MenuItem>
將當前選單的path
作為引數傳遞給menuItem
元件之後,在下一級選單實現時,就能拿到上一級選單的path
值。然後元件中將basepath
的值和當前選單的path
值做一個拼接,作為當前選單的index
值。
<!-- src/menu/menuIndex.vue --> <el-menu-item :index="getPath(child.path)" v-else> </el-menu-item> <script> import path from 'path' export default { name: 'MenuItem',props: ['route','basepath'],data(){ return { } },methods :{ // routepath 為當前選單的path值 // getpath: 拼接 當前選單的上一級選單的path 和 當前選單的path getPath: function(routePath){ return path.resolve(this.basepath,routePath); } } } </script>
再看一下介面。
我們可以看到二級選單的index
值已經沒問題了,但是仔細看,發現工時管理
-工時列表
下的兩個三級選單index
值還是有問題,缺少了工時管理
這個一級選單的path
。
那這個問題是因為我們在呼叫元件自身是傳遞的basepath
有問題。
<!--遞迴呼叫元件自身 --> <MenuItem :route="child.children" :basepath="child.path"> </MenuItem>
basepath
傳遞的只是上一級選單的path
,在遞迴二級選單
時,index
的值是一級選單的path值
+二級選單的path值
;那當我們遞迴三級選單
時,index
的值就是二級選單的path值
+三級選單的path值
,這也就是為什麼工時管理-工時列表
下的兩個三級選單index
值存在問題。
所以這裡的basepath
值在遞迴的時候應該是累積
的,而不只是上一級選單的path
值。因此藉助遞迴演算法的優勢,basepath
的值也需要通過getPath
方法進行處理。
<MenuItem :route="child.children" :basepath="getPath(child.path)"> </MenuItem>
最終完整的程式碼如下。
<!-- src/menu/menuIndex.vue --> <template> <div> <el-submenu v-for="child in route" v-if="child.meta.hasSubMenu" :key="child.path" :index="getPath(child.path)"> <template slot="title"> <i :class="child.meta.icon"></i> <span slot="title"> {{child.meta.title}} </span> </template> <!--遞迴呼叫元件自身 --> <MenuItem :route="child.children" :basepath="getPath(child.path)"> </MenuItem> </el-submenu> <el-menu-item :index="getPath(child.path)" v-else> <i :class="child.meta.icon"></i> <span slot="title"> {{child.meta.title}} </span> </el-menu-item> </div> </template> <script> import path from 'path' export default { name: 'MenuItem',routePath); } } } </script>
刪除其餘用來除錯的程式碼
最終效果
文章的最後呢,將本次實現的最終效果在此展示一下。
選項一
和選項二
這兩個三級選單在路由配置中沒有設定component
,這兩個菜單只是為了實現三級選單,在最後的結果演示中,我已經刪除了路由中配置的這兩個三級選單
此處在leftMenu
元件中為el-menu
開啟了unique-opened
在menuIndex
元件中,將左側選單欄的寬度改為200px
總結
到此這篇關於Vue結合路由配置遞迴實現選單欄功能的文章就介紹到這了,更多相關vue 路由遞迴選單欄內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!