vue的router.addRoutes方法不能在已存在的路由下添加子路由的另类解决办法

官网:router-addroutes

1
2
router.addRoutes(routes: Array<RouteConfig>)
动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。

说得比较简单,假设c是从后台获取到的权限路由,那么:

1
[{path='a'},{path='b'}].addRoutes([{path='c'}]) = [{path='a'},{path='b'},{path='c'}]

可以看出只能往后追加,如果我要c作为a的子路由,变成这样

1
[{path='a',children:[{path='c'}]},{path='b'}

addRoutes方法不能在已存在的路由下添加子路由,具体讨论请看:https://github.com/vuejs/vue-router/issues/1156

下面记录一下我的开发过程:

页面结构为一个大的home页,里面有sysa、sysb、sysc等很多模块,点击任何一个模块都会跳login页,登录一个模块后其他模块也就登录了,所以采用了子路由的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// router/index.js 主路由
import sysaRoutes from '@/views/sysa/routes'
export const constantRoutes = [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
component: () => import('@/views/home/index')
},
{
path: '/login',
component: () => import('@/views/login/index')
},
// 子路由
sysaRoutes,
{
path: '/404',
component: () => import('@/views/error-page/404'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error-page/401'),
hidden: true
},
{
path: '*',
redirect: '/404',
hidden: true
}
]

// views/sysa/sysaRoutes.js 模块路由
import Layout from './layout'
const sysaRoutes = {
path: '/sysa',
component: Layout,
redirect: '/sysa/dashboard',
meta: { title: 'sysa系统', icon: 'dashboard' },
children: [
{
path: 'dashboard',
name: 'dashboard',
component: () => import('./dashboard/index'),
meta: { title: 'sysa首页', icon: 'dashboard', affix: true }
},
{
path: 'index',
name: 'index',
component: () => import('./pro/index'),
meta: { title: '项目列表', icon: 'documentation', noCache: true }
},
// 我要把adminRoutes插入到该位置
]
}
export default sysaRoutes

// router/roles/adminRoutes.js 权限路由
const adminRoutes = [
{
path: 'stat2',
name: 'stat2',
component: () => import('@/views/sysa/stat/stat'),
meta: { title: '统计2', icon: 'documentation', noCache: true },
children: [
{
path: 'stat3',
name: 'stat3',
component: () => import('@/views/sysa/stat/stat'),
meta: { title: '统计3', icon: 'documentation', noCache: true }
},
{
path: 'stat4',
name: 'stat4',
component: () => import('@/views/sysa/stat/stat'),
meta: { title: '统计4', icon: 'documentation', noCache: true }
}
]
}
]
export default adminRoutes
  • 思路1:我把adminRoutes外面包一层,变成sysaRoutes的形式,然后用addRoutes方法,它会直接覆盖addRoutes,失败
  • 思路2:如果有一个方法addRoutes([parentName, ]routes),可以指定父级,那么就简单了,可惜没有这样的方法。找到一个类似的 EnhancedRouter.js,经过测试并不好用,当adminRoutes还有子路由的时候报重复路由,本身是for遍历,对性能太差了,失败
  • 思路3:我获取到原路由,做判断,当r.path===’/sysa’的时候,把adminRoutes加到children里去
    1
    2
    3
    4
    5
    6
    // permission.js 拦截器里
    const accessRoutes = await store.dispatch('permission/generateRoutes', authorities)
    const { routes } = router.options
    const indexRoutes = routes.find(r => r.path === '/sysa')
    indexRoutes.children.push.apply(indexRoutes.children, accessRoutes)
    router.addRoutes([indexRoutes])

这样结构虽然对了,但是破坏了原有observer,所以点击’/sysa/stat2’都是空白页,失败

  • 思路4:既然addRoutes不能添加到子路由,那么我在生成权限路由的时候干脆直接生成sysa,去掉主路由里的sysaRoutes
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // store/modules/permission.js
    import { constantRoutes } from '@/router'
    // 去掉主路由里的sysaRoutes,放到了这里
    import sysaRoutes from '@/views/sysa/routes'
    import zbxSupportRoutes from '@/router/roles/zbxSupportRoutes'
    const state = {
    routes: [],
    addRoutes: []
    }
    const mutations = {
    SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
    }
    }
    const actions = {
    generateRoutes({ commit }, roles) {
    return new Promise(resolve => {
    let accessedRoutes
    if (roles.includes('ROLE_zbxSupport')) {
    sysaRoutes.children.push.apply(sysaRoutes.children, zbxSupportRoutes)
    // 模块路由+权限路由
    accessedRoutes = sysaRoutes
    } else {
    // ...
    }
    commit('SET_ROUTES', accessedRoutes)
    resolve(accessedRoutes)
    })
    }
    }

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

    // permission.js 拦截器里
    const accessRoutes = await store.dispatch('permission/generateRoutes', authorities)
    // 这回这里accessRoutes可是一个完整的{}路由
    router.addRoutes([accessRoutes])

终于成功了

最后侧边要显示模块sysa菜单

1
2
3
4
5
6
7
8
9
10
11
12
computed: {
...mapGetters([
'permission_routes',
'sidebar'
]),
sysa_routes() {
const sysa_routes_obj = this.permission_routes.find(r => r.path === '/sysa')
return sysa_routes_obj.children
}
}
// 注意补上模块跟路由/sysa
:to="'/sysa' + resolvePath(onlyOneChild.path)">

总结,一开始总想着要追加到子路由,舍不得把模块路由去掉,忽略了发挥addRoutes的能力

Author: kyxiao
Link: https://kyxiao.github.io/2019/08/27/vue的router-addRoutes方法不能在已存在的路由下添加子路由的另类解决办法/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.