欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue結(jié)合路由配置遞歸實現(xiàn)菜單欄功能

 更新時間:2020年06月16日 11:57:20   作者:小土豆biubiubiu  
這篇文章主要介紹了Vue結(jié)合路由配置遞歸實現(xiàn)菜單欄,本文通過實例代碼給大家介紹的非常詳細,對大家的學習火鍋工作具有一定的參考借鑒價值,需要的朋友可以參考下

前言

在日常開發(fā)中,項目中的菜單欄都是已經(jīng)實現(xiàn)好了的。如果需要添加新的菜單,只需要在路由配置中新增一條路由,就可以實現(xiàn)菜單的添加。

相信大家和我一樣,有時候會躍躍欲試自己去實現(xiàn)一個菜單欄。那今天我就將自己實現(xiàn)的菜單欄的整個思路和代碼分享給大家。

本篇文章重在總結(jié)和分享菜單欄的一個遞歸實現(xiàn)方式,代碼的優(yōu)化、菜單權限等不在本篇文章范圍之內(nèi),在文中的相關部分也會做一些提示,有個別不推薦的寫法希望大家不要參考哦。

同時可能會存在一些細節(jié)的功能沒有處理或者沒有提及到,忘知曉。

最終的效果

本次實現(xiàn)的這個菜單欄包含有一級菜單、二級菜單三級菜單這三種類型,基本上已經(jīng)可以覆蓋項目中不同的菜單需求。

后面會一步一步從易到難去實現(xiàn)這個菜單。

簡單實現(xiàn)

我們都知道到element提供了 NavMenu 導航菜單組件,因此我們直接按照文檔將這個菜單欄做一個簡單的實現(xiàn)。

基本的布局架構(gòu)圖如下:

菜單首頁-menuIndex

首先要實現(xiàn)的是菜單首頁這個組件,根據(jù)前面的布局架構(gòu)圖并且參考官方文檔,實現(xiàn)起來非常簡單。

<!-- 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: '員工管理系統(tǒng)'
 }
 }
}
</script>
<style lang="scss">
 #menu-index{
 .el-header{
  padding: 0px;
 }
 }
</style>

頂部菜單欄-topMenu

頂部菜單欄主要就是一個logo產(chǎn)品名稱。

邏輯代碼也很簡單,我直接將代碼貼上。

<!-- 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>

這段代碼中包含了父組件傳遞給子組件的兩個數(shù)據(jù)。

props: ['logoPath', 'name']

這個是父組件menuIndex傳遞給子組件topMenu的兩個數(shù)據(jù),分別是logo圖標的路徑產(chǎn)品名稱。

完成后的界面效果如下。

左側(cè)菜單欄-leftMenu

首先按照官方文檔實現(xiàn)一個簡單的菜單欄。

<!-- 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">員工統(tǒng)計</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">考勤統(tǒng)計</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">工時統(tǒng)計</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>

注意菜單的樣式代碼,設置了絕對定位,并且設置topbottom使菜單高度撐滿屏幕。

此時在看下界面效果。

基本上算是實現(xiàn)了一個簡單的菜單布局。

不過在實際項目在設計的時候,菜單欄的內(nèi)容有可能來自后端給我們返回的數(shù)據(jù),其中包含菜單名稱、菜單圖標以及菜單之間的層級關系。

總而言之,我們的菜單是動態(tài)生成的,而不是像前面那種固定的寫法。因此下面我將實現(xiàn)一個動態(tài)生成的菜單,菜單的數(shù)據(jù)來源于我們的路由配置。

結(jié)合路由配置實現(xiàn)動態(tài)菜單

路由配置

首先,我將項目的路由配置代碼貼出來。

import Vue from 'vue';
import Router from "vue-router";

// 菜單
import MenuIndex from '@/components/menu/menuIndex.vue';

// 首頁
import Index from '@/components/homePage/index.vue';

// 人員統(tǒng)計
import EmployeeStatistics from '@/components/employeeManage/employeeStatistics.vue';
import EmployeeManage from '@/components/employeeManage/employeeManage.vue'

// 考勤
// 考勤統(tǒng)計
import AttendStatistics from '@/components/attendManage/attendStatistics';
// 考勤列表
import AttendList from '@/components/attendManage/attendList.vue';
// 異常管理
import ExceptManage from '@/components/attendManage/exceptManage.vue';

// 工時
// 工時統(tǒng)計
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',
 component: MenuIndex,
 redirect: '/employee/employeeStatistics', 
 meta: {
  title: '員工管理', // 菜單標題
  icon: 'el-icon-user-solid', // 圖標
  hasSubMenu: true, // 是否包含子菜單
 },
 children: [
  // 員工統(tǒng)計
  {
  path: 'employeeStatistics',
  name: 'employeeStatistics',
  meta: {
   title: '員工統(tǒng)計', // 菜單標題,
   hasSubMenu: false // 是否包含子菜單
  },
  component: EmployeeStatistics,
  },
  // 員工管理(增刪改查)
  {
  path: 'employeeManage',
  name: 'employeeManage',
  meta: {
   title: '員工管理', // 菜單標題
   hasSubMenu: false // 是否包含子菜單
  },
  component: EmployeeManage
  }
 ]
 },
 // 考勤管理
 {
 path: '/attendManage',
 name: 'attendManage',
 component: MenuIndex,
 redirect: '/attendManage/attendStatistics',
 meta: {
  title: '考勤管理', // 菜單標題
  icon: 'el-icon-s-claim', // 圖標
  hasSubMenu: true, // 是否包含子節(jié)點,false 沒有子菜單;true 有子菜單
 },
 children:[
  // 考勤統(tǒng)計
  {
  path: 'attendStatistics',
  name: 'attendStatistics',
  meta: {
   title: '考勤統(tǒng)計', // 菜單標題 
   hasSubMenu: false // 是否包含子菜單  
  },
  component: AttendStatistics,
  },
  // 考勤列表
  {
  path: 'attendList',
  name: 'attendList',
  meta: {
   title: '考勤列表', // 菜單標題 
   hasSubMenu: false // 是否包含子菜單   
  },
  component: AttendList,
  },
  // 異常管理
  {
  path: 'exceptManage',
  name: 'exceptManage',
  meta: {
   title: '異常管理', // 菜單標題 
   hasSubMenu: false // 是否包含子菜單   
  },
  component: ExceptManage,
  }
 ]
 },
 // 工時管理
 {
 path: '/timeManage',
 name: 'timeManage',
 component: MenuIndex,
 redirect: '/timeManage/timeStatistics',
 meta: {
  title: '工時管理', // 菜單標題
  icon: 'el-icon-message-solid', // 圖標
  hasSubMenu: true, // 是否包含子菜單,false 沒有子菜單;true 有子菜單
 },
 children: [
  // 工時統(tǒng)計
  {
  path: 'timeStatistics',
  name: 'timeStatistics',
  meta: {
   title: '工時統(tǒng)計', // 菜單標題
   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: '選項二', // 菜單標題
    hasSubMenu: false // 是否包含子菜單 
   },
   },
  ]
  }
 ]
 },
];
export default new Router({
 routes
})

在這段代碼的最開始部分,我們引入了需要使用的組件,接著就對路由進行了配置。

此處使用了直接引入組件的方式,項目開發(fā)中不推薦這種寫法,應該使用懶加載的方式

路由配置除了最基礎的path、component以及children之外,還配置了一個meta數(shù)據(jù)項。

meta: {
 title: '工時管理', // 菜單標題
 icon: 'el-icon-message-solid', // 圖標
 hasSubMenu: true, // 是否包含子節(jié)點,false 沒有子菜單;true 有子菜單
}

meta數(shù)據(jù)包含的配置有菜單標題(title)、圖標的類名(icon)和是否包含子節(jié)點(hasSubMenu)。

根據(jù)title、icon這兩個配置項,可以展示當前菜單的標題圖標。

hasSubMenu表示當前的菜單項是否有子菜單,如果當前菜單包含有子菜單(hasSubMenutrue),那當前菜單對應的標簽元素就是el-submenu;否則當前菜單對應的菜單標簽元素就是el-menu-item。

是否包含子菜單是一個非常關鍵的邏輯,我在實現(xiàn)的時候是直接將其配置到了meta.hasSubMenu這個參數(shù)里面。

根據(jù)路由實現(xiàn)多級菜單

路由配置完成后,我們就需要根據(jù)路由實現(xiàn)菜單了。

獲取路由配置

既然要根據(jù)路由配置實現(xiàn)多級菜單,那第一步就需要獲取我們的路由數(shù)據(jù)。這里我使用簡單粗暴的方式去獲取路由配置數(shù)據(jù):this.$router.options.routes。

這種方式也不太適用日常的項目開發(fā),因為無法在獲取的時候?qū)β酚勺鲞M一步的處理,比如權限控制。

我們在組件加載時打印一下這個數(shù)據(jù)。

// 代碼位置:src/menu/leftMenu.vue
 mounted(){
 console.log(this.$router.options.routes);
}

打印結(jié)果如下。

可以看到這個數(shù)據(jù)就是我們在router.js中配置的路由數(shù)據(jù)。

為了方便使用,我將這個數(shù)據(jù)定義到計算屬性中。

// 代碼位置:src/menu/leftMenu.vue
computed: {
 routesInfo: function(){
 return this.$router.options.routes;
 }
}

一級菜單

首先我們來實現(xiàn)一級菜單

主要的邏輯就是循環(huán)路由數(shù)據(jù)routesInfo,在循環(huán)的時候判斷當前路由route是否包含子菜單,如果包含則當前菜單使用el-submenu實現(xiàn),否則當前菜單使用el-menu-item實現(xiàn)。

<!-- src/menu/leftMenu.vue -->
<el-menu 
 :default-active="$route.path" 
 class="el-menu-vertical-demo" 
 :collapse="false">
 <!-- 一級菜單 -->
 <!-- 循環(huán)路由數(shù)據(jù) -->
 <!-- 判斷當前路由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>

結(jié)果:

可以看到,我們第一級菜單已經(jīng)生成了,員工管理、考勤管理、工時管理這三個菜單是有子菜單的,所以會有一個下拉按鈕。

不過目前點開是沒有任何內(nèi)容的,接下來我們就來實現(xiàn)這三個菜單下的二級菜單。

二級菜單

二級菜單的實現(xiàn)和一級菜單的邏輯是相同的:循環(huán)子路由route.children,在循環(huán)的時候判斷子路由childRoute是否包含子菜單,如果包含則當前菜單使用el-submenu實現(xiàn),否則當前菜單使用el-menu-item實現(xiàn)。

那話不多說,直接上代碼。

<!-- src/menu/leftMenu.vue -->
<el-menu 
 :default-active="$route.path" 
 class="el-menu-vertical-demo" 
 :collapse="false">
 <!-- 一級菜單 -->
 <!-- 循環(huán)路由數(shù)據(jù) -->
 <!-- 判斷當前路由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>
 <!-- 二級菜單 -->
 <!-- 循環(huán)子路由`route.children` -->
 <!-- 循環(huán)的時候判斷子路由`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>

結(jié)果如下:

可以看到二級菜單成功實現(xiàn)。

三級菜單

三級菜單就不用多說了,和一級、二級邏輯相同,這里還是直接上代碼。

<!-- src/menu/leftMenu.vue -->
<el-menu 
 :default-active="$route.path" 
 class="el-menu-vertical-demo" 
 :collapse="false">
 <!-- 一級菜單 -->
 <!-- 循環(huán)路由數(shù)據(jù) -->
 <!-- 判斷當前路由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>
 <!-- 二級菜單 -->
 <!-- 循環(huán)子路由`route.children` -->
 <!-- 循環(huán)的時候判斷子路由`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>
  <!-- 三級菜單 -->
  <!-- 循環(huán)子路由`childRoute.children` -->
  <!-- 循環(huán)的時候判斷子路由`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>

可以看到工時列表下的三級菜單已經(jīng)顯示了。

總結(jié)

此時我們已經(jīng)結(jié)合路由配置實現(xiàn)了這個動態(tài)的菜單。

不過這樣的代碼在邏輯上相關于三層嵌套for循環(huán),對應的是我們有三層的菜單。

假如我們有四層五層甚至更多層的菜單時,那我們還得在嵌套更多層for循環(huán)。很顯然這樣的方式暴露了前面多層for循環(huán)的缺陷,所以我們就需要對這樣的寫法進行一個改進。

遞歸實現(xiàn)動態(tài)菜單

前面我們一直在說一級、二級、三級菜單的實現(xiàn)邏輯都是相同的:循環(huán)子路由,在循環(huán)的時候判斷子路由是否包含子菜單,如果包含則當前菜單使用el-submenu實現(xiàn),否則當前菜單使用el-menu-item實現(xiàn)。那這樣的邏輯最適合的就是使用遞歸去實現(xiàn)。

所以我們需要將這部分共同的邏輯抽離出來作為一個獨立的組件,然后遞歸的調(diào)用這個組件。

邏輯拆分

<!-- 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>

需要注意的是,這次抽離出來的組件循環(huán)的時候直接循環(huán)的是route數(shù)據(jù),那這個route數(shù)據(jù)是什么呢。

我們先看一下前面三層循環(huán)中循環(huán)的數(shù)據(jù)源分別是什么。

為了看得更清楚,我將前面代碼中一些不相關的內(nèi)容進行了刪減。

<!-- 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>

從上面的代碼可以看到:

一級菜單循環(huán)的是`routeInfo`,即最初我們獲取的路由數(shù)據(jù)`this.$router.options.routes`,循環(huán)出來的每一項定義為`route`

二級菜單循環(huán)的是`route.children`,循環(huán)出來的每一項定義為`childRoute`

三級菜單循環(huán)的是`childRoute.children`,循環(huán)出來的每一項定義為`child`

按照這樣的邏輯,可以發(fā)現(xiàn)二級菜單、三級菜單循環(huán)的數(shù)據(jù)源都是相同的,即前一個循環(huán)結(jié)果項的children,而一級菜單的數(shù)據(jù)來源于this.$router.options.routes。

前面我們抽離出來的menuItem組件,循環(huán)的是route數(shù)據(jù),即不管是一層菜單還是二層三層菜單,都是同一個數(shù)據(jù)源,因此我們需要統(tǒng)一數(shù)據(jù)源。那當然也非常好實現(xiàn),我們在調(diào)用組件的時候,為組件傳遞不同的值即可。

代碼實現(xiàn)

前面公共組件已經(jīng)拆分出來了,后面的代碼就非常好實現(xiàn)了。

首先是抽離出來的meunItem組件,實現(xiàn)的是邏輯判斷以及遞歸調(diào)用自身。

<!-- 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>
  <!--遞歸調(diào)用組件自身 -->
  <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組件,調(diào)用menuIndex組件,傳遞原始的路由數(shù)據(jù)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>

最終的結(jié)果這里就不展示了,和我們需要實現(xiàn)的結(jié)果是一致的。

功能完善

到此,我們結(jié)合路由配置實現(xiàn)了菜單欄這個功能基本上已經(jīng)完成了,不過這是一個缺乏靈魂的菜單欄,因為沒有設置菜單的跳轉(zhuǎn),我們點擊菜單欄還無法路由跳轉(zhuǎn)到對應的組件,所以接下來就來實現(xiàn)這個功能。

菜單跳轉(zhuǎn)的實現(xiàn)方式有兩種,第一種是NavMenu組件提供的跳轉(zhuǎn)方式。

第二種是在菜單上添加router-link實現(xiàn)跳轉(zhuǎn)。

那本次我選擇的是第一種方式實現(xiàn)跳轉(zhuǎn),這種實現(xiàn)方式需要兩個步驟才能完成,第一步是啟用el-menu上的router;第二步是設置導航的index屬性。

那下面就來實現(xiàn)這兩個步驟。

啟用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

首頁 

員工管理 
 員工統(tǒng)計 index="/employee/employeeStatistics"
 員工管理 index="/employee/employeeManage"

考勤管理 
 考勤統(tǒng)計 index="/attendManage/attendStatistics"
 考勤列表 index="/attendManage/attendList"
 異常管理 index="/attendManage/exceptManage"

員工統(tǒng)計 
 員工統(tǒng)計 index="/timeManage/timeStatistics"
 員工統(tǒng)計 index="/timeManage/timeList"
 選項一 index="/timeManage/timeList/options1"
 選項二 index="/timeManage/timeList/options2"

接著在回顧前面遞歸調(diào)用的組件,導航菜單的index設置的是child.path,為了看清楚child.path的值,我將其添加菜單標題的右側(cè),讓其顯示到界面上。

<!-- 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>
 <!--遞歸調(diào)用組件自身 -->
 <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>

然后我們看一下效果。

可以發(fā)現(xiàn),child.path的值就是當前菜單在路由中配置path值(router.js中配置的path值)。

那么問題就來了,前面我們整理了每一個菜單標題對應需要設置的index屬性值,就目前來看,現(xiàn)在設置的index值是不符合要求的。不過仔細觀察現(xiàn)在菜單設置的index值和正常值是有一點接近的,只是缺少了上一級菜單的path值,如果能將上一級菜單path值和當前菜單的path值進行一個拼接,就能得到正確的index值了。

那這個思路實現(xiàn)的方式依然是在遞歸時將當前菜單的path作為參數(shù)傳遞給menuItem組件。

<!-- src/menu/menuIndex.vue -->
<!--遞歸調(diào)用組件自身 -->
<MenuItem 
 :route="child.children" 
 :basepath="child.path">
</MenuItem>

將當前菜單的path作為參數(shù)傳遞給menuItem組件之后,在下一級菜單實現(xiàn)時,就能拿到上一級菜單的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值已經(jīng)沒問題了,但是仔細看,發(fā)現(xiàn)工時管理-工時列表下的兩個三級菜單index值還是有問題,缺少了工時管理這個一級菜單的path

那這個問題是因為我們在調(diào)用組件自身是傳遞的basepath有問題。

<!--遞歸調(diào)用組件自身 -->
<MenuItem 
 :route="child.children" 
 :basepath="child.path">
</MenuItem>

basepath傳遞的只是上一級菜單的path,在遞歸二級菜單時,index的值是一級菜單的path值+二級菜單的path值;那當我們遞歸三級菜單時,index的值就是二級菜單的path值+三級菜單的path值,這也就是為什么工時管理-工時列表下的兩個三級菜單index值存在問題。

所以這里的basepath值在遞歸的時候應該是累積的,而不只是上一級菜單的path值。因此借助遞歸算法的優(yōu)勢,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>
  <!--遞歸調(diào)用組件自身 -->
  <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',
 props: ['route','basepath'],
 data(){
 return {
  
 }
 },
 methods :{
 // routepath 為當前菜單的path值
 // getpath: 拼接 當前菜單的上一級菜單的path 和 當前菜單的path
 getPath: function(routePath){
  return path.resolve(this.basepath, routePath);
 }
 }
}
</script>

刪除其余用來調(diào)試的代碼

最終效果

文章的最后呢,將本次實現(xiàn)的最終效果在此展示一下。

選項一選項二這兩個三級菜單在路由配置中沒有設置component,這兩個菜單只是為了實現(xiàn)三級菜單,在最后的結(jié)果演示中,我已經(jīng)刪除了路由中配置的這兩個三級菜單

此處在leftMenu組件中為el-menu開啟了unique-opened

menuIndex組件中,將左側(cè)菜單欄的寬度改為200px

總結(jié)

到此這篇關于Vue結(jié)合路由配置遞歸實現(xiàn)菜單欄功能的文章就介紹到這了,更多相關vue 路由遞歸菜單欄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • vue-cli構(gòu)建項目使用 less的方法

    vue-cli構(gòu)建項目使用 less的方法

    這篇文章主要介紹了vue-cli構(gòu)建項目使用 less,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • vue開發(fā)中關于axios的封裝過程

    vue開發(fā)中關于axios的封裝過程

    這篇文章主要介紹了vue開發(fā)中關于axios的封裝過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • vue+element實現(xiàn)表單校驗功能

    vue+element實現(xiàn)表單校驗功能

    這篇文章主要介紹了vue+element表單校驗功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-05-05
  • Vue2打包部署后可動態(tài)修改后端接口地址的解決方法

    Vue2打包部署后可動態(tài)修改后端接口地址的解決方法

    本篇文章將介紹使用Vue2開發(fā)前后端分離項目時,前端打包部署后可動態(tài)修改后端接口地址的解決方法,文中通過圖文結(jié)合的方式介紹的非常詳細,需要的朋友可以參考下
    2024-07-07
  • vue驗證碼組件使用方法詳解

    vue驗證碼組件使用方法詳解

    這篇文章主要為大家詳細介紹了vue驗證碼組件的使用方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • WebSocket使用以及在vue如何使用問題

    WebSocket使用以及在vue如何使用問題

    這篇文章主要介紹了WebSocket使用以及在vue如何使用問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • vue element自定義表單驗證請求后端接口驗證

    vue element自定義表單驗證請求后端接口驗證

    這篇文章主要介紹了vue element自定義表單驗證請求后端接口驗證,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • Vue+Electron打包桌面應用(超詳細完整教程)

    Vue+Electron打包桌面應用(超詳細完整教程)

    這篇文章主要介紹了Vue+Electron打包桌面應用超詳細完整教程,在這大家要記住整個項目的json文件不能有注釋,及時沒報錯也不行,否則運行命令時還是有問題,具體細節(jié)問題參考下本文詳細講解
    2024-02-02
  • vue結(jié)合el-table實現(xiàn)表格行拖拽排序(基于sortablejs)

    vue結(jié)合el-table實現(xiàn)表格行拖拽排序(基于sortablejs)

    這篇文章主要介紹了vue結(jié)合el-table實現(xiàn)表格行拖拽排序(基于sortablejs),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-01-01
  • vue 使用高德地圖vue-amap組件過程解析

    vue 使用高德地圖vue-amap組件過程解析

    這篇文章主要介紹了vue 使用高德地圖vue-amap組件過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09

最新評論