动态路由-刷新页面时的bug修复
1.问题说明
- 如果我们刷新浏览器,会发现跳到了404页面
- 对于addRoute添加的路由,在刷新时会白屏
2.问题分析
解决页面刷新时,页面 404 问题
- 在静态路由后面有一个路由通配符,addRoutes添加的路由是异步添加的。
- 路由设置中的404页处在中间位置,而不是所有路由的末尾了,
path:'*'
导致可以匹配任意页面
解决动态路由,刷新页面白屏问题
- 已知 Vue- router 的Bug
- 凡是 addRoutes 动态添加的路由,必须在重新调用一下 next() 并且需要手动指定路径才可以。
3.解决
(1) 解决页面刷新时,页面 404 问题
- 把404页改到路由配置的最末尾就可以了
filterRoutes.push(
{ path: '*', redirect: '/404', hidden: true }
)
(2) 解决动态路由,刷新页面白屏问题
next({
path: to.path, // 保证路由添加完了再进入页面 (可以理解为重进一次)
replace: true // 重进一次, 不保留重复历史
})
完整代码
router.beforeEach(async(to, from, next) => {
// 设置当前页面标题
document.title = getPageTitle(to.meta.title)
// 获取 token
const token = store.state.user.token
// 显示进度条效果
NProgress.start()
// 判断 token 是否存在
if (token) {
// 是否是登录页面 、
if (to.path === '/login') {
// 如果有 token,访问登录页面,跳转到主页
next('/')
} else {
// 如果有 token,访问不是登录页面,直接放行
// 1.判断是否存在用户信息(已经将用户信息存到 Vuex 中)
if (!store.getters.userId) {
// 2.如果没有用户信息,需要获取用户信息 --> 用户权限信息
// ** 获取用户信息的时机:**
// 1.因为依赖 token 去获取用户数据,所以必须要在获取了token 之后才能调用这个 action 函数
// 2.因为跳转到首页之后就要显示数据了,所以要求我们在跳转进入首页之前就提前拿回用户个人数据
const menus = await store.dispatch('user/getUserInfo')
// 3.根据后台返回的权限信息,从本地预置的 8 个路由里面筛选出当前用户有权访问的路由
const filterRoutes = asyncRoutes.filter(route => {
// 获取到每一个路由规则的名称
const routeName = route.children[0].name
// 判断获取到的路由名称在不在 menus 权限信息中
return menus.includes(routeName)
})
// 解决页面刷新 404 的问题
// 就是将通配符放置到筛选好的路由最后面
filterRoutes.push({ path: '*', redirect: '/404', hidden: true })
// 通过 addRoutes 动态添加的路由,是存到内存中的,并不会对 routes 产生影响
router.addRoutes(filterRoutes)
// 5.左侧菜单是从 Vue-router 中的 routes 获取的数据进行渲染,将左侧菜单数据获取方式进行调整(Vuex)
// 将动态路由传递给 mutation 方法,进行合并
store.commit('permission/setRoutes', filterRoutes)
// 通过 addRoutes 添加的路由,访问以后可能存在白屏的问题
// 原因是 Vue-router 的已知 Bug
// 之前是没有这些动态路由的,然后我们使用 addRoutes 添加以后才有的路由规则
// 如果这时候想访问动态添加的路由,必须手动告诉 Vue-router 我要去哪里
next({ path: to.path, replace: true }) // 会调用 router.replace 方法,清空之前的浏览历史,等于是重新进入路由
}
// ** 动态路由的处理时机:**
// 1.先获取到用户信息
// 2.跳转之前
// ** 思路:**
// 1.判断是否存在用户信息(已经将用户信息存到 Vuex 中)
// 2.如果没有用户信息,需要获取用户信息 --> 用户权限信息
// 3.根据后台返回的权限信息,从本地预置的 8 个路由里面筛选出当前用户有权访问的路由
// 4.使用 Vue-router 提供的 addRoutes 方法,将筛选出来的路由添加到路由对象中
// 5.左侧菜单是从 Vue-router 中的 routes 获取的数据进行渲染,将左侧菜单数据获取方式进行调整(Vuex)
next()
}
} else {
// 判断访问的路由在不在白名单
if (whiteList.includes(to.path)) {
// 如果没有 token,但在白名单中,则放行
next()
} else {
// 如果没有 token,也不在白名单中,则跳转到登录页
next('/login')
}
}
// 手动强制关闭一次 为了解决 手动切换地址时 进度条的不关闭的问题
NProgress.done()
})