有一個菜單樹,頂層菜單下面有多個子菜單,子菜單下還有子菜單。。。
這時候就要用遞歸處理css
修改 src/router/index.js 的 / 路由vue
{ path: '/', redirect: '/dashboard', name: 'Container', component: Container, children: [ {path: 'dashboard', name: '首頁', component: Dashboard, children: [ {path: 'dashboard1', name: '首頁1', component: Dashboard,}, {path: 'dashboard2', name: '首頁2', component: Dashboard, children: [ {path: 'dashboard21', name: '首頁21', component: Dashboard,}, {path: 'dashboard22', name: '首頁22', component: Dashboard, }, ] }, ] }, {path: 'article', name: '文章', component: Article, }, ] }
生成的遞歸路由放在側邊欄,所以抽取 sidebar 組件,sidebar 包含logo和 遞歸路由
再抽取 SidebarItem 爲單獨的路由組件,方便遞歸調用數組
Sidebar 接收collapse、路由數組,同時引入 SidebarItem 組件bash
子組件傳入:app
<template> <div> <div class="app-side-logo"> <img src="@/assets/logo.png" :width="collapse ? '60' : '60'" height="60" /> </div> <el-menu class="el-menu-vertical-demo" :default-active="defaultActive" router :collapse="collapse" > <SidebarItem v-for="(item, idx) in routes" :subroute="item" :fatherpath="fatherPath" :barIdx="idx" :key="idx" /> </el-menu> </div> </template> <script> import SidebarItem from './SidebarItem' export default { naem: "Sidebar", components: { SidebarItem }, props: { collapse: { type: Boolean }, routes: { type: Array } }, computed: { // 首次進入頁面時展開當前頁面所屬的菜單 defaultActive(){ return this.$route.path }, fatherPath(){ // 這裏直接獲取路由配置的 '/' 項 return this.$router.options.routes[1].path } } } </script> <style> </style>
SidebarItem 接收路由、父路由path、父級idx,而後遞歸調用自身ide
<template> <!-- 若是當前 subroute 有子節點 --> <el-submenu v-if="!subroute.hidden && subroute.children && subroute.children.length > 0" :index="genPath(fatherpath, subroute.path)"> <!-- 建立菜單分組 --> <template slot="title"> <i class="el-icon-menu"></i> <span slot="title">{{subroute.name}}</span> </template> <!-- 遞歸調用自身,直到 subroute 不含子節點 --> <SidebarItem v-for="(submenu, subidx) in subroute.children" :subroute="submenu" :fatherpath="genPath(fatherpath, subroute.path)" :barIdx="subidx" :key="barIdx + '-' + subidx" /> </el-submenu> <!-- 當前節點不含子節點且非隱藏 --> <el-menu-item style="font-weight: 400" v-else-if="!subroute.hidden" :index="genPath(fatherpath, subroute.path)" >{{subroute.name}} </el-menu-item> <el-menu-item style="font-weight: 400" v-else :index="genPath(fatherpath, subroute.path)" >{{ subroute.name }} </el-menu-item> </template> <script> export default { name: 'SidebarItem', props: { subroute: { type: Object }, barIdx: { type: [String, Number] }, fatherpath: { type: String } }, computed: { // 默認激活的路由, 用來激活菜單選中狀態 defaultActive: function(){ return this.$route.path }, }, methods: { // 生成側邊欄路由,格式: /a/b/c genPath: function(){ let arr = [ ...arguments ] let path = arr.map(v => { while (v[0] === '/'){ v = v.substring(1) } while(v[-1] === '/'){ v = v.substring(0, v.length) } return v }).join('/') path = path[0] === '/' ? path : '/'+path return path }, handleOpen: function(key, keyPath) { console.log(key, keyPath) }, handleClose: function(key, keyPath) { console.log(key, keyPath) } }, mounted: function(){ console.log('sidebar routes: ', this.routes) } } </script> <style> </style>
此時 src 的目錄結構this
│ App.vue │ main.js ├─assets │ logo.png ├─components │ HelloWorld.vue │ Sidebar.vue │ SidebarItem.vue ├─container │ Container.vue ├─router │ index.js ├─styles │ index.scss └─views │ TheLogin.vue ├─article │ index.vue └─dashboard index.vue
src/container/Container.vue 引入 Sidebar 組件spa
<template> <!-- ... --> <el-aside class="app-side app-side-left" :class="isCollapse ? 'app-side-collapsed' : 'app-side-expanded'"> <Sidebar :collapse="isCollapse" :routes="$router.options.routes[1].children"/> </el-aside> <!-- ... --> </template> <script> import Sidebar from '@/components/Sidebar' export default { name: 'Container', components: { Sidebar }, /** ... */ </script>
頁面效果 code