vue动态路由

246 阅读2分钟

动态路由主要采用的是router.addRoutes添加动态路由

思路分析

  1. 前后端数据需要进行对比,动态路由需要给父级路由设置默认重定向
    • 在utils包中定义两个方法
    • 主要采用递归的方式
  2. 采用路由导航守卫,对路由跳转进行监控,判断其是否登录,是否有权限,并添加动态路由等
  3. 在store中处理动态路由

代码实现

  • 导航守卫
import router from './index'
import store from '../store/index'
router.beforeEach((to, from, next) => {
  if (!store.state.userToken) {
    // 未登录
    if (!to.name || to.matched.some(record => record.meta.requireAuth)) {
      // 页面需要登录
      // matched存放了路径的所有路由,包括父路由和子路由
      // 父路由或子路由中的任意一个路由‘requireAuth’为真,都要跳转到登录页
      // 也就是在设置时,只需要将父路由的requireAuth=true,就可以控制所有子路由了
      next({ path: '/login' })
    } else {
      next()
    }
  } else {
    // 已登录 判断权限
    if (to.path === '/login') {
      // 已登录不能再去登录页面
      next('/')
    } else if (store.state.permissions.permissionRoutes.length === 0) {
      // 动态路由还未加载
      // 加载动态路由
      store.dispatch('setRoutes', store.state.userToken).then(routes => {
        // 添加动态路由
        router.addRoutes(routes)
        // 使用以下方法,可以中断当前导航,再次进入导航守卫,这样可以确保addRoutes已完成
        next({ ...to, replace: true })
      })
    } else {
      if (to.name) {
        next()
      } else {
        // 路由不存在就去404页面
        next('/404')
      }
    }
  }
})
  • store中处理动态路由
import { getPermissions } from '../../api/permission.js'
import { dynamicDefaultRoutes } from '@/router/index.js'
import { diffRoutes, defaultRoute } from '@/utils/deal-route.js'
import dynamicRoutes from '../../router/dynamic-routes'

export default {
  state: {
    permissionRoutes: [] // 存储动态路由
  },
  mutations: {
    SET_ROUTES(state, routes) {
      state.permissionRoutes = routes
    },
    CLEAR_ROUTES(state) {
      state.permissionRoutes = null
    }
  },
  actions: {
    async setRoutes({ commit }, token) {
      // 获取后台路由权限
      let res = await getPermissions({ user: token })
      // 对比后台权限与前端所有动态路由,得到有权限的路由
      let routes = diffRoutes(dynamicRoutes, res.data)
      // 处理动态路由的重定向
      defaultRoute(routes)
      // 获取默认路由中的layout根路由,并将动态路由设置为其子路由
      let container = dynamicDefaultRoutes.find(r => r.path === '')
      container.children.push(...routes)
      commit('SET_ROUTES', dynamicDefaultRoutes)
      // 返回动态路由,在路由导航中添加动态路由
      return dynamicDefaultRoutes
    }
  }
}
  • utils对比动态路由和设置默认路由方法
// 对比前后端路由,获取有权限的动态路由
export function diffRoutes(allroutes = [], userRoutes = []) {
  const realRoutes = [] 
  allroutes.forEach(r => {
    userRoutes.forEach(item => {
      if (r.meta.name === item.name) {
        if (item.children && item.children.length > 0) {
          // 递归处理子路由
          r.children = diffRoutes(r.children, item.children)
        } else {
          r.children = []
        }
        realRoutes.push(r)
      }
    })
  })
  return realRoutes
}

// 为路由设置重定向,默认是当前路由的第一个子路由
export function defaultRoute(allroutes) {
  allroutes.forEach(r => {
    if (r.children && r.children.length > 0) {
      r.redirect = r.path + '/' + r.children[0].path
      // 递归处理子路由
      defaultRoute(r.children)
    }
  })
}

注意: vue-router新版本下,router.addRoutes已被废弃;使用 route.addRoute() 代替

for (let x of routes) { router.addRoute(x) }