避坑! router.addroutes 动态添加路由表实现侧边栏有效更新

2,844 阅读2分钟

前言

通常使用Vue2.x开发后台管理系统会涉及到根据用户权限动态渲染侧边栏的需求。以前手动维护路由的方式比较繁杂,在Vue2.2之后通过新增的router.addroutes可以方便动态添加路由了。

Api

  addRoutes (routes: RouteConfig[]): void;
  //动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。

动态路由渲染过程

先介绍下实现侧边栏动态渲染的大致方式:

配置静态路由表:

// router.js
export const constantRouterMap = [{
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },]

配置需要动态渲染的路由表:

// router.js
export const asyncRouterMap = [{
    path: '/admin',
    component: () => import('@/views/admin/index'),
    hidden: true,
    meta: {
          title: 'xxx', // 标题
          icon: 'xxx', // 图标
          role: ['admin'] // 角色权限字段
        }
    },
    {
        ...
        //其它动态路由列表,这里不过多展示
    }]

用户在登陆页进行登录成功跳转至首页时,利用导航守卫router.beforeEach()发起ajax请求获取用户信息,再从用户信息中拿到对应的role字段,再与asyncRouterMap[i].meta.role进行比对,将比对结果作为条件滤出角色所属的路由表。

//permission.js
router.beforeEach(async (to, from, next) => {
  // 验证用户是否已经登陆过
  const hasToken = getToken()
  if (hasToken) {
    if (to.path === '/login') {
    //是否跳转登录页
      next({
        path: '/'
      })
    } else {
      //这一步为了路由数据持久化,防止刷新后vuex数据丢失造成的侧边栏显示异常
      const hasGetRouters = store.getters.routers
      //是否已经获取用户信息
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo && hasGetRouters.length) {
        next()
      } else {
        try {
        //获取角色信息
          const {
            role
          } = await store.dispatch('user/getInfo')
          //传入角色信息,执行过滤方法 这里可自行实现,不过多赘述
          await store.dispatch('permission/getRoutes', {
            role
          })
          //添加动态路由
          router.addRoutes(store.getters.addRouters);
          next({
            ...to,
            replace: true
          })
        } catch (error) {
        }
      }
    }
  }
})

遇到的坑

  • 我已经成功添加动态路由了,为什么使用router.addRoutes添加的动态路由没有在router.options中更新?

    作者有提到 That is normal, options is the object passed to the vuerouter constructor. It's not modified afterwards。其实相应的路由已经添加了,只是内部将动态路由参数传给了VueRouter构造函数,所以无法在VueRouter实例中看到。

  • 既然侧边栏不能通过v-for="route in $router.options"渲染,如何才能实现有效更新?

    因为使用router.addRoutes来进行添加路由无法更新this.$router.options,所以主要的实现方法是通过store来存储路由表。

//store
const state = {
  routers: [],
  addRouters: []
}

const mutations = {
  SET_ROUTERS: (state, routers) => {
    state.addRouters = routers;
    //与静态路由表拼接
    state.routers = constantRouterMap.concat(routers);
  }
}
const actions = {
  getRoutes({
    commit
  }, data) {
    return new Promise(resolve => {
      const {
        role
      } = data;
      
          ...
          //过滤出role对应路由表accessedRouters
      commit('SET_ROUTERS', accessedRouters);
      resolve();
    })
  }
}
//sideBar.vue

    ...mapState("permission", {
      routers: "routers",
    }),
  • 使用Vuex存储路由表,但刷新之后侧边栏显示空白?

因为Vuex无法持久化保存数据,在页面刷新之后数据被清空,所以需要在router.beforeEach()内再做一层判断页面是否刷新,来判断是否进行持久化。