vue-router-3.0.1 使用router.addRoutes()
设置动态,动态路由对应页面直接刷新后无效
问题总述
vue-router-3.0.1 使用router.addRoutes()
设置动态路由,从非动态路由(router初始化时就存在的路由)页面跳转到动态添加的路由的页面,一切正常。但是,在动态添加的路由的页面刷新后(即动态路由对应的页面自己刷新再路由到自己),路由匹配失败,页面无法渲染。
详细介绍
最近做一个小项目,vue相关依赖版本如:
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"
项目中,用户登录系统前,初始默认路由如下:
/**
* 静态路由
*/
export const staticRouters = [{
path: '/',
redirect: '/Home'
}, {
path: '/Home',
component: Wrapper,
children: [{
path: '',
name: 'Home',
component: Home
}],
meta: {
name: '首页'
}
}, {
path: '/DiscussZone',
component: Wrapper,
children: [{
path: '',
name: 'DiscussZone',
component: DiscussZone
}],
meta: {
name: '讨论区'
}
}, {
path: '/Login',
name: 'Login',
component: Login
}, {
path: '/Register',
name: 'Register',
component: Register
}]
/**
* "个人中心" 子路由
*/
export const myCenterRouter = [{
path: '',
redirect: '/MyCenter/myGame'
}, {
path: 'myGame',
name: 'myGame',
component: MyGame,
meta: {
name: '我发布的比赛'
}
}, {
path: 'myPostings',
name: 'myPostings',
component: MyPostings,
meta: {
name: '我的帖子'
}
}]
/**
* 动态路由
*/
export const dynamicRouters = [{
path: '/MyCenter',
component: Wrapper,
children: [{
path: '',
component: MyCenter,
children: myCenterRouter
}],
meta: {
name: '个人中心'
}
}, {
path: '*',
name: '404',
component: NotFound
}]
// 实例化初始静态路由
export default new Router({
routes: staticRouters
})
在vux中,state
中设置“用户信息”userInfo
字段,其中uid
为用户登录唯一ID,getters
中根据uid
来计算用户未登录/登录状态下的可用功能模块和动态路由。
// vuex store/index.js
...
state: {
userInfo: {
uid: '',
role: ''
}
},
...
getters: {
// 计算用户登陆后功能模块
userStatusMenu: state => {
// 根据vuex中用户id是否有值,判断返回的功能菜单模块
return !state.userInfo.uid ? state.staticMenuList : state.staticMenuList.concat(state.dynamicMenuList)
},
// 计算用户登陆后动态路由
userDynamicRouters: state => {
// 根据vuex中用户id是否有值,判断返回的动态路由
return !state.userInfo.uid ? [] : dynamicRouters
}
},
mutations: {
// 保存/更新用户信息
SET_USER_INFO(state, userInfo) {
// state.userInfo = Object.assign({}, state.userInfo, userInfo)
state.userInfo.uid = userInfo
}
},
现在要实现如下功能:
用户登录前,系统菜单栏只有“首页”、“讨论区”两个功能以及对应的初始路由。当用户登录系统后,动态添加“个人中心”模块和其对应路由。
个人实现机制如下:
1.用户登录前,实例化“首页”和“讨论区”的初始路由
// router/index.js
...
export default new Router({
routes: staticRouters
})
...
2.当用户登录系统后,将用户uid
写入浏览器sessionStorage
中(后面用户强制刷新页面时,要使用其判断),同时提交mutation
,设置vue
x中stat
e的uesrInfo.uid
字段,此时,uid
字段改变,便会重新计算getters
中的用户菜单栏(userStatusMenu)
,在系统菜单栏动态添加“个人中心”模块入口,并计算出该模块的动态新增的路由userDynamicRouters
。
3.vuex
中gettes
计算求得需要动态新增的路由userDynamicRouters
后,使用router.addRoutes
`(userDynamicRouters)添加动态路由到初始化的路由实例对象
router`。
login() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
this.$store.commit('SET_USER_INFO', '1234567890') // 1.登陆成功,vuex设置用户id
sessionStorage.setItem('userUuid', '1234567890') // 2.session同时存储id,手动刷新页面时用它重写vuex用户id
this.$router.addRoutes(this.userDynamicRouters) // 3.追加动态路由
this.$router.push('/Home') // 4.跳转到首页
} else {
this.$message.warning('请完善登录信息!')
return false
}
})
}
至此,初步解决了根据用户登录状态动态生成系统菜单栏功能模块入口和添加动态路由功能。登陆后,动态添加的“个人中心”模块也可以正常路由。
但是系统页面F5或者Ctrl+F5刷新后,因为刷新页面vuex
和router
实例会重新初始化到初始状态,所以vuex
中state.userInfo.uid
和新增的动态路由会被刷掉。
所以,在main.js中设置全局路由守卫router.beforeEach()
,当页面刷新时重新判断登录时存储的localStorage
中uid
字段,如果存在,说明用户登录,此时如果vuex
中state.userInfo.uid
如果为空,说明是用户登录后进行了刷新页面的操作,此时会重新向vuex
提交mutation
,设置state.userInfo.uid
,并重新计算动态路由,再addRotes()
到路由实例router
。如下:
// 路由跳转前,登录状态判断
router.beforeEach((to, from, next) => {
let userUid = sessionStorage.getItem('userUuid')
// sessionStorage中userUid不为空,说明用户已登录
if (userUid) {
// vue中state.userInfo.uid为空,说明用户刷新了页面
if (!store.state.userInfo.uid) {
store.commit('SET_USER_INFO', userUid) // 重新提交mutation,设置state.userInfo.uid
router.addRoutes(store.getters.userDynamicRouters) // 添加动态路由
}
next()
} else {
// 没有登录信息,说明没有登录
if (to.path.indexOf('/MyCenter') !== -1) {
next('/Home')
} else {
next()
}
}
});
至此解决了页面刷新时,动态路由失效的问题。
但是,But,However,我遇到了一个的坑,也是这篇帖子最后想问的问题!!前面交代那么多,就是想把自己实现的机制描述清楚,方便大神带带我,指导一下!!
我遇到的坑和问题
这个坑是:我在“首页”、“讨论区”这种router初始化时就存在的模块中点击菜单跳转到动态路由模块“个人中心”包括在这些页面刷新页面后再跳转“个人中心”时,一切路由都正常!But,但是,在进入“个人中心”,也就是路由到动态增加的动态路由后,在动态路由页面直接刷新页面,却无法正常路由,页面没有渲染!!
找了半天,google,度娘找了一圈,也没找到处理方法!小弟愚钝,请大神赐教!!帮忙看看什么原因?
上述代码中第一个if中的next()改为next({...to})