vue-element-admin 实现动态路由(从后台查询出菜单列表绑定侧边栏)

1. 在路由实例中保留基础路由

router/index.js中只需要保留基础路由,其他的都删了




2. 获取用户菜单,并保存到Vuex中

stroe/modules/user.js中,有个getInfo方法查询用户基本信息,返回了用户的菜单列表



复制代码

// get user info

  getInfo({ commit, state }) {

    return new Promise((resolve, reject) => {

      getInfo(state.token).then(response => {

        const { data } = response

        if (!data) {

          reject('Verification failed, please Login again.')

        }

        console.log(data)

        const menus =

        [{

          path: '/books',

          component: 'Layout',

          children: [{

            path: 'index',

            name: 'AddressBook',

            component: 'workbench/addressbook',

            meta: { title: '通讯录', icon: 'company' }

          }]

        },

        {

          path: '/systool',

          component: 'Layout',

          redirect: '/systool/coder',

          name: 'SysTool',

          meta: { title: '实验室', icon: 'example' },

          children: [

            {

              path: 'calendar',

              name: 'Calendar',

              component: 'workbench/calendar',

              meta: { title: '日程', icon: 'table' }

            }

          ]

        }]

        const { name, avatar, companyName, employeeid } = data

        commit('SET_NAME', name)

        commit('SET_AVATAR', avatar)

        commit('SET_CMPNAME', companyName)

        commit('SET_USERID', employeeid)

        commit('SET_MENUS', menus)

        resolve(data)

      }).catch(error => {

        reject(error)

      })

    })

  }

复制代码


复制代码

const getters = {

  sidebar: state => state.app.sidebar,

  device: state => state.app.device,

  token: state => state.user.token,

  avatar: state => state.user.avatar,

  name: state => state.user.name,

  cmpname: state => state.user.cmpname,

  userid: state => state.user.userid,

  menus: state => state.user.menus

}

export default getters

复制代码

3.动态生成权限路由(核心)

根据环境配置导入组件,在vue中,将菜单路径作为参数,实现路由地址的注入


在 src/router 文件夹下,建立两个文件,各只需添加一行代码, 定义导入方法


src/router/_import_development.js

//开发环境导入组件

module.exports = file => require('@/views' + file + '.vue').default // vue-loader at least v13.0.0+


---------------------------------------------------------------------


src/router/_import_production.js

//生产环境导入组件

module.exports = file => () => import('@/views' + file + '.vue')

A,组件导入 —— _import


//获取组件的方法

const _import = require('./router/_import_' + process.env.NODE_ENV)


// .......


//导入路径下的组件

route.component = _import(route.path)

B,在路由钩子中,过滤路由,并生成路由


核心在src目录下的permission.js中,router.beforeEach路由钩子


 import router from './router'

 import store from './store'

 import {

   Message

 } from 'element-ui'

 import NProgress from 'nprogress' // progress bar

 import 'nprogress/nprogress.css' // progress bar style

 import {

   getToken

 } from '@/utils/auth' // get token from cookie

 import getPageTitle from '@/utils/get-page-title'

 import Layout from '@/layout'

 const _import = require('./router/_import_' + process.env.NODE_ENV) // 获取组件的方法

 

 NProgress.configure({

   showSpinner: false

 }) // NProgress Configuration

 

 const whiteList = ['/login'] // no redirect whitelist

 

 router.beforeEach(async(to, from, next) => {

   // start progress bar

   NProgress.start()

 

   // set page title

   document.title = getPageTitle(to.meta.title)

 

   // determine whether the user has logged in

   const hasToken = getToken()

 

   if (hasToken) {

     if (to.path === '/login') {

       // if is logged in, redirect to the home page

       next({

         path: '/'

       })

       NProgress.done()

     } else {

       const hasGetUserInfo = store.getters.name

       if (hasGetUserInfo) {

         next()

       } else {

         try {

           // get user info

           await store.dispatch('user/getInfo')

           if (store.getters.menus.length < 1) {

             global.antRouter = []

             next()

           }

           const menus = filterAsyncRouter(store.getters.menus) // 1.过滤路由

           router.addRoutes(menus) // 2.动态添加路由

           global.antRouter = menus // 3.将路由数据传递给全局变量,做侧边栏菜单渲染工作

           next({

             ...to,

             replace: true

           }) // hack方法 确保addRoutes已完成 ,set the replace

         } catch (error) {

           // remove token and go to login page to re-login

           await store.dispatch('user/resetToken')

           Message.error(error || 'Has Error')

           next(`/login?redirect=${to.path}`)

           NProgress.done()

         }

       }

     }

   } else {

     /* has no token*/

 

     if (whiteList.indexOf(to.path) !== -1) {

       // in the free login whitelist, go directly

       next()

     } else {

       // other pages that do not have permission to access are redirected to the login page.

       next(`/login?redirect=${to.path}`)

       NProgress.done()

     }

   }

 })

 

 router.afterEach(() => {

   // finish progress bar

   NProgress.done()

 })

 

 // 遍历后台传来的路由字符串,转换为组件对象

 function filterAsyncRouter(asyncRouterMap) {

   const accessedRouters = asyncRouterMap.filter(route => {

     if (route.component) {

       if (route.component === 'Layout') {

         route.component = Layout

       } else {

         route.component = _import(route.component) // 导入组件

       }

     }

     if (route.children && route.children.length) {

       route.children = filterAsyncRouter(route.children)

     }

     return true

   })

 

   return accessedRouters

 }

4.最后一步,合并路由


有话要说