ElementUIでの動的ルーティングの分析と実装

1.動的ルーティングの分析

  1. 動的ルーティングの生成ロジックは次のとおりです。
  • ユーザーロールの@router読み取りasyncRoutesconstantRoutes取得からrolesrolesを含めるかどうかを決定しますadmin
  • 保存たフィルターrolesが含まれている場合。adminasyncRoutesvuex
  • roles含まれていない場合admin、トラバースroutesしてアクセスルートかどうかを判断します。そうでない場合は、トラバースを続けますroutesその場合、ルートが含まれてchildrenいるかどうかを確認します。含まれている場合はchildren、トラバースchildren、フィルタリングchildren、更新tmp.childrenしてからパスインして、ルートが含まれてchildrenいるかどうかを判断します。そうでない場合はchildren、に保存されresたフィルタールートasyncRoutesvuex
  • フィルターasyncRoutesに保存されvuex、中央、asyncRoutesおよびconstantRoutesマージ。

第二に、動的ルーティングの実現

  1. キーは、ルーティング動的生成する方法であるpremission.jsgenerateRoutes次のようにコードである、方法。
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. mutationsSET_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
}

おすすめ

転載: blog.csdn.net/weixin_42614080/article/details/107829515