Vue-element-admin动态加载路由学习

关于vue-element-admin中动态加载路由

主要的两个js文件为src/permission.js和store/models/permission.js

src/perminssion.js 比较关键的代码如下:

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

  NProgress.start()

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

  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        try {
          const { roles } = await store.dispatch('user/getInfo')
          const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
          router.addRoutes(accessRoutes)
          next({ ...to, replace: true })
        } catch (error) {
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

可知在permission.js文件中 通过调用router.beforeEach()方法再每次请求时判断获取用户的详细信息和通过用户信息中的角色构造路由

const { roles } = await store.dispatch('user/getInfo')
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)

router.addRoutes(accessRoutes)

vuex 对应的user/getInfo 行为的代码为

getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const { data } = response

        if (!data) {
          reject('Verification failed, please Login again.')
        }

        const { roles, name, avatar, introduction } = data

        // roles must be a non-empty array
        if (!roles || roles.length <= 0) {
          reject('getInfo: roles must be a non-null array!')
        }

        commit('SET_ROLES', roles)
        commit('SET_NAME', name)
        commit('SET_AVATAR', avatar)
        commit('SET_INTRODUCTION', introduction)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

可知,用户在登录的情况下都会通过vuex请求一次都向后端发送了一次getInfo()请求获取用户最新的数据信息并提交role,name,avatar,introuction等信息存于vuex

当js执行到此处时

const accessRoutes = await store.dispatch('permission/generateRoutes', roles)

该语句对应的vuex permission/generateRoutes行为的代码则需要重点关注store/permission.js这个文件

store/modules/permission.js的内容如下

import { asyncRoutes, constantRoutes } from '@/router'

function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    return true
  }
}

export function filterAsyncRoutes(routes, roles) {
  const res = []

  routes.forEach(route => {
    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    }
  })

  return res
}

const state = {
  routes: [],
  addRoutes: []
}

const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
  }
}

const actions = {
  generateRoutes({ commit }, roles) {
    return new Promise(resolve => {
      let accessedRoutes
      if (roles.includes('admin')) {
        accessedRoutes = asyncRoutes || []
      } else {
        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      }
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

前面提到src/permission.js 向vuex分发了permission/generateRoutes并将roles作为参数传递给vuex,通过方法名可知其功能就是完成创建路由的行为该方法会返回可访问路由accessedRoutes

而对应的行为代码为上面代码的generateRoutes方法,该行为通过判断传递过来的roles中是否包含admin这个角色,如果有则将动态路由asyncRoutes赋值给accessedRoutes,如果不包含则调用filterAsyncRoutes()方法将动态路由asyncRoutes和roles传递到该方法中,filterAsyncRoutes()通过判断route.meta.roles是否存在对应的角色,将具有对应角色的路由添加到res中并返回给accessedRoutes

再commit('SET_ROUTES', accessedRoutes) 提交

最后当代码执行到src/permission.js的

router.addRoutes(accessRoutes)

调用router.addRoutes()方法添加可访问的路由列表

总结

vue-element-admin默认的动态路由加载是通过判断router中的meta.roles是否包含对应的role,并进行加载指定的路由,而这些路由都写在了router/index.js文件中,那么后端则只需要进行角色的分配然后由前端的store/perminss.js的filterAsyncRoutes

动态构建路由并加载说白了后端就是相当于不用分配每个角色对应的权限和菜单 因为这部分的都有store/perminss.js中方法进行动态构建了