博客
关于我
Element UI 中动态路由的分析及实现
阅读量:359 次
发布时间:2019-03-05

本文共 6946 字,大约阅读时间需要 23 分钟。

一、动态路由的分析

  1. 动态路由的生成逻辑,如下所示:
  • @router 读取 asyncRoutesconstantRoutes,获取用户角色 roles,判断 roles 是否包含 admin
  • 如果 roles 是包含 admin,将过滤后的 asyncRoutes 保存到 vuex 中。
  • 如果 roles 不包含 admin,那么遍历 routes,判断是否具有路由访问权限。如果不具备,继续遍历 routes。如果具备,判断路由是否包含 children。如果包含 children,遍历 children,过滤 children,更新 tmp.children,再传入判断路由是否包含 children。如果不包含 children,将路由存入 res,将过滤后的 asyncRoutes 保存到 vuex 中。
  • 将过滤后的 asyncRoutes 保存到 vuex 中后,asyncRoutesconstantRoutes 进行合并。

二、动态路由的实现

  1. 生成动态路由的关键方法是 premission.js 中的 generateRoutes 方法,代码如下所示:
const actions = {     // 生成动态路由的关键方法  generateRoutes({    commit }, roles) {       // 返回 Promise 对象    return new Promise(resolve => {         let accessedRoutes      if (roles.includes('admin')) {           // 如果角色中包含 admin,则直接跳过判断,直接将 asyncRoutes 全部返回        accessedRoutes = asyncRoutes || []      } else {           // 如果角色中不包含 admin,则调用 filterAsyncRoutes 过滤路由        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)      }      // 将路由保存到 vuex 中      commit('SET_ROUTES', accessedRoutes)      resolve(accessedRoutes)    })  }}
  1. mutations 中的 SET_ROUTES,代码如下所示:
const mutations = {     SET_ROUTES: (state, routes) => {       // 将 routes 保存到 state 中的 addRoutes    state.addRoutes = routes    // 将 routes 集成到 src/router/index.js 中的 constantRoutes 中    state.routes = constantRoutes.concat(routes)  }}
  1. 路由过滤的方法 filterAsyncRoutes,代码如下所示:
/** * @param routes 异步加载的路由 * @param roles  用户的角色,数组形式 */// 路由过滤export function filterAsyncRoutes(routes, roles) {     const res = []  // 遍历全部的路由  routes.forEach(route => {       // 对路由进行浅拷贝,注意 children 不会拷贝,因为不需要对 children 进行判断,所有可以直接使用    const tmp = {    ...route }    // 检查用户角色是否具备访问路由的权限    if (hasPermission(roles, tmp)) {         // 当路由具备访问的权限时,判断路由是否具备 children 属性      if (tmp.children) {           // 当路由包含 children 时,对 children 迭代调用 filterAsyncRoutes 方法        tmp.children = filterAsyncRoutes(tmp.children, roles)      }      // 当路由具有访问权限时,将 tmp 保存到 res 中      res.push(tmp)    }  })  return res}
  1. 检查权限的方法 hasPermission,代码如下所示:
// 检查权限的方法function hasPermission(roles, route) {     // 检查路由是否包含 meta 和 meta.roles 属性  if (route.meta && route.meta.roles) {       // 判断 route.meta.roles 中是否包含用户角色 roles 中的任何一个权限,如果包含则返回 true    return roles.some(role => route.meta.roles.includes(role))  } else {       // 如果路由没有 meta 或 meta.roles 属性,则视为该路由不需要进行权限控制,所有用户对该路由可访问    return true  }}
  1. 完整的核心代码,如下所示:
    premission.js
import {    asyncRoutes, constantRoutes } from '@/router'// 检查权限的方法function hasPermission(roles, route) {     // 检查路由是否包含 meta 和 meta.roles 属性  if (route.meta && route.meta.roles) {       // 判断 route.meta.roles 中是否包含用户角色 roles 中的任何一个权限,如果包含则返回 true    return roles.some(role => route.meta.roles.includes(role))  } else {       // 如果路由没有 meta 或 meta.roles 属性,则视为该路由不需要进行权限控制,所有用户对该路由可访问    return true  }}// 路由过滤export function filterAsyncRoutes(routes, roles) {     const res = []  // 遍历全部的路由  routes.forEach(route => {       // 对路由进行浅拷贝,注意 children 不会拷贝,因为不需要对 children 进行判断,所有可以直接使用    const tmp = {    ...route }    // 检查用户角色是否具备访问路由的权限    if (hasPermission(roles, tmp)) {         // 当路由具备访问的权限时,判断路由是否具备 children 属性      if (tmp.children) {           // 当路由包含 children 时,对 children 迭代调用 filterAsyncRoutes 方法        tmp.children = filterAsyncRoutes(tmp.children, roles)      }      // 当路由具有访问权限时,将 tmp 保存到 res 中      res.push(tmp)    }  })  return res}const state = {     routes: [],  addRoutes: []}const mutations = {     SET_ROUTES: (state, routes) => {       // 将 routes 保存到 state 中的 addRoutes    state.addRoutes = routes    // 将 routes 集成到 src/router/index.js 中的 constantRoutes 中    state.routes = constantRoutes.concat(routes)  }}const actions = {     // 生成动态路由的关键方法  generateRoutes({    commit }, roles) {       // 返回 Promise 对象    return new Promise(resolve => {         let accessedRoutes      if (roles.includes('admin')) {           // 如果角色中包含 admin,则直接跳过判断,直接将 asyncRoutes 全部返回        accessedRoutes = asyncRoutes || []      } else {           // 如果角色中不包含 admin,则调用 filterAsyncRoutes 过滤路由        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)      }      // 将路由保存到 vuex 中      commit('SET_ROUTES', accessedRoutes)      resolve(accessedRoutes)    })  }}export default {     namespaced: true,  state,  mutations,  actions}

user.js

import {    login, logout, getInfo } from '@/api/user'import {    getToken, setToken, removeToken } from '@/utils/auth'import router, {    resetRouter } from '@/router'const state = {     token: getToken(),  name: '',  avatar: '',  introduction: '',  roles: []}const mutations = {     SET_TOKEN: (state, token) => {       state.token = token  },  SET_INTRODUCTION: (state, introduction) => {       state.introduction = introduction  },  SET_NAME: (state, name) => {       state.name = name  },  SET_AVATAR: (state, avatar) => {       state.avatar = avatar  },  SET_ROLES: (state, roles) => {       state.roles = roles  }}const actions = {     login({    commit }, userInfo) {       const {    username, password } = userInfo    return new Promise((resolve, reject) => {         login({    username: username.trim(), password: password }).then(response => {           const {    data } = response        commit('SET_TOKEN', data.token)        setToken(data.token)        resolve()      }).catch(error => {           reject(error)      })    })  },  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        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)      })    })  },  logout({    commit, state, dispatch }) {       return new Promise((resolve, reject) => {         logout(state.token).then(() => {           commit('SET_TOKEN', '')        commit('SET_ROLES', [])        removeToken()        resetRouter()        dispatch('tagsView/delAllViews', null, {    root: true })        resolve()      }).catch(error => {           reject(error)      })    })  },  resetToken({    commit }) {       return new Promise(resolve => {         commit('SET_TOKEN', '')      commit('SET_ROLES', [])      removeToken()      resolve()    })  },  async changeRoles({    commit, dispatch }, role) {       const token = role + '-token'    commit('SET_TOKEN', token)    setToken(token)    const {    roles } = await dispatch('getInfo')    resetRouter()    const accessRoutes = await dispatch('permission/generateRoutes', roles, {    root: true })    router.addRoutes(accessRoutes)    dispatch('tagsView/delAllViews', null, {    root: true })  }}export default {     namespaced: true,  state,  mutations,  actions}

转载地址:http://rppg.baihongyu.com/

你可能感兴趣的文章
Web前端安全策略之CSRF的攻击与防御
查看>>
5分钟快速了解下CSS4 color-adjust属性
查看>>
纯客户端页面关键字搜索高亮jQuery插件
查看>>
秋月何时了,CSS3 border-radius知多少?
查看>>
linux运维中常用的命令
查看>>
M1芯片的macbook安装王者荣耀,原神,崩坏方法
查看>>
CentOS7更改成阿里云的源
查看>>
Java温故而知新-反射机制
查看>>
Netty3事件处理顺序问题
查看>>
eclipse引用sun.misc开头的类
查看>>
firefox中angular2嵌套发送请求问题
查看>>
Netty 知识整理 (2)HttpServerCodec和HttpObjectAggregator用法
查看>>
【Linux】service命令
查看>>
【mysql】事务隔离与mvcc的误区
查看>>
【mybatis3】调试/断点打印日志
查看>>
【linux】pid file解读
查看>>
Leetcode 102题.从中序与后序遍历序列构造二叉树
查看>>
C++
查看>>
[CTFSHOW]PHP特性
查看>>
navigator对象
查看>>