前言
最近公司的一个后台管理系统技术太老,太难维护了,于是跟组长提出重构的想法,组长决定把大旗交给我,刚好尤大大发布vue3,不容置疑,技术选型vue3和element-plus这对好闺蜜,在后端接口不变的情况下进行重构,也就是说只改前端,后端不动,顿时觉得这段时间不能摸鱼了
正文
总所周知,后台最不可缺失的是根据权限获取动态路由,在这里遇到了一个问题,当我用addRoues添加路由的时候居然报错,查查了文档才发现,哦~~~
一开始还以为看错了,怎么有两个addRoute,一度觉得官方是不是写错了,被逼无奈还是接受了,没有就没有啦,用addRoute也是可以的,于是创建permission文件:
// permission.js
import router from './router'
// 获取处理好的路由
let routes= await store.dispatch('user/getRoutes')
routes.forEach(item => router.addRoute(item))
next()
好了,这样确实是没问题,当你刷新页面的时候,见证奇迹的时刻到了
获取不到路径,这么说是路由是没添加进去吗? 幸好路由提供了getRoutes用来获取路由记录,重新整理一下
// permission.js
import router from './router'
// 获取处理好的路由
let routes= await store.dispatch('user/getRoutes')
routes.forEach(item => router.addRoute(item)
+ console.log(router.getRoutes(), 'getRoutes')
next()
打印出来看到的是路由已经添加进去了
想了想,难道是执行循序的问题?井底之蛙,一直摸你肚子(真相只有一个)
我的理解是这样的,当你刷新页面的时候,vue会重新实例化,并且进入路由拦截,还没执行addRoute时,路由还没被添加进去,这就解释了vue提示没有这个路径。
那为什么白屏呢?
哎,还没说完,当你执行到addRoute时,路由要添加进去了,但是,路由不是响应式的,从执行循序来看,地址栏快于路由的添加,那找不到这个路径了就只能白屏了,除非设置了404的页面
如何解决? 很简单,只需要再进一次拦截就好啦
完整实现
// permission.js
// 记录路由
+ let hasRoles = true
// 白名单(不需要登录就可以访问的名单)
const whiteList = ['/login']
router.beforeEach(async (to, form, next) => {
let userInfo = getStorage('userInfo')?.accountId
if (userInfo) {
// 如果有token
if (to.path === '/login') {
// 如果是登录状态 并且进入的页面是登录页面 则跳到首页
next({ path: '/' })
} else {
// 获取处理好的路由
let routes= await store.dispatch('user/getRoutes')
// 路由添加进去了没有及时更新 需要重新进去一次拦截
+ if (hasRoles) {
routes.forEach(item => router.addRoute(item))
+ hasRoles = false
+ next({ ...to, replace: true }) // 这里相当于push到一个页面 不在进入路由拦截
+ } else {
next() // 如果不传参数就会重新执行路由拦截,重新进到这里
+ }
}
} else {
if (whiteList.includes(to.path)) {
next()
} else {
next(`/login?redirect=${to.path}`)
}
}
})
这样就解决刷新出现白屏啦。
补充(不用next参数)
查阅了vue-router4.x文档,发现next参数事可选的,因此可以不用再管next这个难理解的东西了,我们来重构一下
let hasRoles = true
NProgress.configure({ showSpinner: false })
// 白名单(不需要登录就可以访问的名单)
const whiteList = ['/login']
router.beforeEach(async to => {
// 进度条开始
NProgress.start()
let userInfo = getStorage('userInfo')?.accountId
if (userInfo) {
// 如果有token
if (to.path === '/login') {
// 如果是登录状态 并且进入的页面是登录页面 则跳到首页
router.push({ path: '/' })
NProgress.done()
} else {
// 获取路由
let routes = await store.dispatch('user/getRoutes')
// 路由添加进去了没有及时更新 需要重新进去一次拦截
if (hasRoles) {
routes.forEach(item => router.addRoute(item))
hasRoles = false
router.push({ ...to, replace: true })
}
}
} else {
if (!whiteList.includes(to.path)) {
router.push({ path: '/login' })
}
}
})
有没有感觉看得清楚明了了很多
写在最后
这是我在掘金写的第二篇文章,相比第一篇内容丰富很多,字数也饱满了,这个主题也是我在项目中遇到的,也在百度参考了很多大神的做法,但普遍都说next({ ...to, replace: true })改成这样就可以了,具体也没说原因,cv缺又不行,进入了死循环,困扰了一天,所以写这篇文章的初心是希望遇到这个问题的朋友们可以知道为什么会出现白屏,并且如何解决,各位可能觉得这种办法不太好,欢迎提出更好的方法,也欢迎提出建议和质疑