vue+elementui搭建後臺管理界面(5遞歸生成側欄路由)

有一個菜單樹,頂層菜單下面有多個子菜單,子菜單下還有子菜單。。。
這時候就要用遞歸處理css

1 定義多級菜單

修改 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, },
    ]
  }

2 抽出Sidebar組件

生成的遞歸路由放在側邊欄,所以抽取 sidebar 組件,sidebar 包含logo和 遞歸路由
再抽取 SidebarItem 爲單獨的路由組件,方便遞歸調用數組

2.1 Sidebar

Sidebar 接收collapse、路由數組,同時引入 SidebarItem 組件bash

子組件傳入:app

  • barIdx: 當前路由的索引,用來定位子菜單
  • subroute: 路由對象
  • fatherpath: 父路徑,如 /、 /a/b
<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>

2.2 SidebarItem

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>

3 項目結構

此時 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

4 修改容器配置

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

相關文章
相關標籤/搜索