• vue+elementui搭建后台管理界面(5递归生成侧栏路由)


    有一个菜单树,顶层菜单下面有多个子菜单,子菜单下还有子菜单。。。
    这时候就要用递归处理

    1 定义多级菜单

    修改 src/router/index.js 的 / 路由

      {
        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 组件

    子组件传入:

    • 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,然后递归调用自身

    <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 的目录结构

    │  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 组件

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

    页面效果

  • 相关阅读:
    Python的第一个程序
    Spring Boot 之Web开发
    JAVA简介及特性
    Spring Boot与Docker
    ls命令之通配符的使用
    [导入]ASP.NET常用函数
    [导入]再见号称中国最美的女人
    [导入]www.reactos.org一网友介绍的方向为“自己写操作系统的站点”
    [导入] Gmail Chat (Gmail 里的聊天功能)
    [导入]此篇写给城里普通收入的年轻人~~~
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/9977220.html
Copyright © 2020-2023  润新知