vue-router+vuex的坑

问题描述

最近使用vue-h5-template写一个移动端demo,想配合后端搞一个动态路由,于是想起以前使用过的vue-element-admin项目里的动态路由方案,大概思路就是准备两个路由数组,一个是不需要经过角色过滤的constantRoutes,一个是需要根据角色过滤的asyncRoutes,在用户登录的时候根据用户角色来过滤asyncRoutes,并将路由信息存放到vuex中

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
// 不需要经过用户角色过滤的路由,也就是任何人都可以看到的
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true,
name: 'Login',
meta: {
title: '登录'
}
},
{
path: '/register',
component: () => import('@/views/register/index'),
hidden: true,
name: 'Register',
meta: {
title: '注册'
}
},
{
path: '/',
component: () => import('@/views/layouts/index'),
redirect: '/my',
meta: {
title: '首页',
keepAlive: false
},
children: []
},
{
path: '/404',
name: '404',
component: () => import('@/views/404/index'),
hidden: true
}
]
// 需要根据用户角色过滤的路由
export const asyncRoutes = [
...userRouter,
// 这个一定要放到最后,匹配不到路由的时候会走该路由,我这里是匹配不到路由就回my页面
{path: '*', redirect: '/my', hidden: true}
]

坑一

路由配置缺少了{path: '*', redirect: '/my', hidden: true}{path: '*', redirect: '/my', hidden: true}没在路由数组的最后一个。
path:'*'表示匹配任何路由,一般来重定向到404页面,将该配置放到路由数组最后,来达到没有匹配到前边/login、/register和asyncRoutes等路由时,走path:'*'路由,我这里没有重定向至404,而是重定向到my页面

坑二

vuex的数据在刷新页面时会丢失,导致在页面刷新后,存储于vuex中的router丢失,从而导致部分路由找不到

解决

因为roles也是在vuex中存储,在路由守卫中来判断roles是否为空,如果为空,则重新请求后端获取roles构建路由

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
router.beforeEach(async (to, from, next) => {
// start progress bar
// NProgress.start()

// set page title
document.title = defaultSettings.title

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

if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({path: '/'})
// NProgress.done()
} else {
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
// 构建动态路由
// get user info
const {roles} = await store.dispatch('user/getInfo')
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
for (const accessRoute of accessRoutes) {
router.addRoute(accessRoute)
}
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')
Toast.fail(error || 'Has Error')
// next(`/login?redirect=${to.path}`)
next(`/login?redirect=${to.path}`)
// NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
// next(`/login?redirect=${to.path}`)
next(`/login?redirect=${to.path}`)
// NProgress.done()
}
}
})