Vue and Vue-Element-Admin (3): Routing and the difference between constantRoutes and asyncRoutes

The router of Vue-Element-Admin always uses constantRoutes and asyncRoutes to define routes. In store.modules.permission.js, there is a default judgment method for the permissions of the two, and then the navigation guard is performed in permission.js in the root directory. logic;

constantRoutes: routes that do not require dynamic judgment permissions, such as login pages, 404, and other general pages;

asyncRoutes : pages that need to dynamically determine permissions and dynamically added through addRoutes;

 1. Implementation of dynamic routing in vue-element-admin

The index.js under the router folder is the project’s total routing entry. After index.js registers the module, it will add in by default constantRoutes non-privileged routing. Maintain static + dynamic routing permissions in store/modules/permission.js and store it in the root The permission.js under the directory implements the navigation guard logic, in /router/index.js:

// router/index.js 部分代码

// 模块化,首先引入在modules目录下需要用的router
import componentsRouter from './modules/components'
import chartsRouter from './modules/charts'
import tableRouter from './modules/table'
import nestedRouter from './modules/nested'
import yzgTest from './modules/yzg'

//constantRoutes 是静态路由,不需要动态权限判断
export const constantRoutes = []
//constantRoutes 是动态路由,需要动态权限判断
export const asyncRoutes = []

// 
const createRouter = () => new Router({
  // mode: 'history', // require service support
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router

A global state array is maintained in store/modules/permission.js, which maintains the menu permissions of the currently logged-in user, and completes the switch of dynamic routing when routing guards, and the dynamic routing of the state state in store/modules/permission.js The maintenance logic is as follows:

// 首先,从index.js中引入已经定义过的2个router数组
import { asyncRoutes, constantRoutes } from '@/router'

// 全局变量state,routes和addRoutes数组
const state = {
  routes: [],
  addRoutes: []
}

// mutations 是唯一可以更改state的函数,使用SET_ROUTES定义更改方法,SET_ROUTES(state, routes)的入参routes赋值给addRoutes数组,将constantRoutes静态路由数组增加routes;

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

// vue中store状态管理,通过actions调用 mutations 中封装的方法来实现对于state更改,
// 这里是vue-element-admin中动态路由的主要判断逻辑发生地方,首先判定用户角色是否包含admin(可能多角色),是则将所有asyncRoutes 加入到constantRoutes,若用户角色没有包含admin,则调用filterAsyncRoutes函数,递归地判定asyncRoutes.roles属性是否有该角色,即是否有权限,将有权限的router赋值accessedRoutes 后加入到constantRoutes;

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

//-----------------
// 两个上面使用的方法
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
}

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

 Finally, look at the routing guard logic in permission.js in the root directory,

// vue-element-admin中permission.js中导航守卫逻辑

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'

// 进度条
NProgress.configure({ showSpinner: false }) // NProgress Configuration
// 白名单
const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist

// 路由之前,逻辑判定
router.beforeEach(async(to, from, next) => {
  // 开始进度条
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  // 有token,如果想去login则调到首页,如果是其他页面先判定是否有角色,有的话就跳过去,没有的话发请求得到永不信息,再调用函数维护store路由列表,报错要么没权限,要么是请求超时,就要返回error,清除token,返回登录页

// 没有token,且不是白名单内的,返回登录页
  if (hasToken) {
    if (to.path === '/login') {
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
    } else {
      // determine whether the user has obtained his permission roles through getInfo
      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) {
          // 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 {

    if (whiteList.indexOf(to.path) !== -1) {
      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()
})

 AsyncRoutes deliberately uses meta.roles to define roles, so after the back-end request returns the user's role, the judgment logic can be linked in permission.js;

Two, routing in vue

Vue-router is the official routing plugin of Vue.js, deeply integrated with vue.js, used to set access paths and map paths and components. Traditional page applications use some hyperlinks to switch pages and jump. In the vue-router single-page application, it is the switching between paths, that is, the switching of components. The essence of the routing module is to establish the mapping relationship between the URL and the page . vue-router provides Hash mode and History mode in implementing single-page front-end routing.

router.push(location)=window.history.pushState
To navigate to a different URL, use the router.push method. This method will add a new record to the history stack, so when the user clicks the browser back button, it will return to the previous URL;

Guess you like

Origin blog.csdn.net/yezonggang/article/details/109809019