解决vue3,动态添加路由,刷新页面出现白屏或者404
1.解决出现刷新页面,出现404的情况
1.问题的出现
在做毕设的时候,在权限路由得到时候,我问通过router**.**addRoute(item)的方式,在路由守卫动态添加路由
刚开始没什么问题,页面的都能正常显示,网络请求也能发送,后来出现了刷新页面,跳转到404
原因:没有将404路由进行动态的添加,而是将他放到了静态路由表里,这就会导致动态的路由会出现404后面,匹配动态路由的时候
上错误代码:
routes = [ { path: '/', redirect: '/login', hidden: true }, { path: '/login', name: 'login', component: () => import('@/views/Login/index.vue'), hidden: true }, { path: '/register', name: 'register', component: () => import('@/views/Register/index.vue'), hidden: true }, // 首页 { path: '/home', name: 'home', component: Layout, redirect: '/home/index', children: [ { path: 'index', meta: { title: '首页', icon: 'HomeFilled' }, component: () => import('@/views/home/index.vue') } ] }, { path: '/personal', name: 'personal', component: Layout, children: [ { path: 'userinfo', meta: { title: '个人信息' }, component: () => import('@/views/Personal/userinfo.vue') }, { path: 'password', meta: { title: '修改密码' }, component: () => import('@/views/Personal/password.vue') } ] }, //404 { path: '/:cachAlll(.*)', component: () => import('@/components/common/404.vue'), hidden: true } ]
复制
解决方法
-
提取出404代码片段
复制const cachAlll = { path: '/:cachAlll(.*)', component: () => import('@/components/common/404.vue'), hidden: true } -
追加到处理好的权限列表的末尾
筛选出用户的权限路由函数,后来发现我的这种方法有点笨
`
/** * 用户权限认证 */ const permission = userStore.userInfo.permission function permissionAuth(data) { return permission?.includes(data) } function hasPermission(data) { let homeMenu = [] data.forEach((item) => { //有permission的路由才做判断,没有的直接放进数组 if (item.permission && !item.children) { if (permissionAuth(item.permission)) { homeMenu.push(item) } } else if (item.permission && item.children) { let obj = {} if (permissionAuth(item.permission)) { obj = { ...item, children: [] } item.children.forEach((child) => { if (permissionAuth(child.permission)) { obj.children.push(child) } }) } // 判断obj是否为空 if (obj.router) { homeMenu.push(obj) } } else { homeMenu.push(item) } }) return homeMenu }
复制
//router/index.js let filterRouter = hasPermission(asyncRouter) filterRouter.push(cachAlll)
复制
我项目采用的vue-router是4.3.3版本 ```js //路由前置守卫 router.beforeEach(async (to, from) => { console.log('路由前置守卫') const userStore = useUserStore() const token = userStore.token // 1.在白名单 if (whiteList.includes(to.path)) { return true } // 2.不在白名单 if (!whiteList.includes(to.path) && !token) { console.log('不在白名单') return '/login' } // 3.有token if (token) { // 3.1.判断有没有用户信息 if (JSON.stringify(userStore.userInfo) === '{}') { // 获取用户信息 await userStore.getUserInfo() } // 3.2.判断有没有权限路由 if (userStore.permissionRouter.length == 0) { await userStore.getUserInfo() let filterRouter = hasPermission(asyncRouter) //**************************************此处添加向数组404****************************************************** filterRouter.push(cachAlll) // 添加动态路由 filterRouter.forEach((item) => { router.addRoute(item) }) // 打印动态路由以进行调试 console.log('动态路由:', filterRouter) console.log(router.getRoutes()) userStore.permissionRouter = [...routes, ...filterRouter] } return true } })
复制
2.白屏现象
如果按照上面那种方法,可以解决刷新页面出现404的问题,但是会出现白屏的现象
但是为什么会出现404,404的出现是因为没有匹配到任务栏的地址,可是我们已经动态的添加了路由,所以为什么检测不到页面呢????
我参考的别人的博客https://blog.csdn.net/qq_37150410/article/details/128012829?fromshare=blogdetail&sharetype=blogdetail&sharerId=128012829&sharerefer=PC&sharesource=weixin_65363325&sharefrom=from_link,采用了他的方法
具体原因就是:路由守卫里进行的动态路由初始化行不通,因为在进路由守卫之前,程序已经进行了路由匹配,结果就是没匹配到任何内容,自然就报错了。
这是我的打印
可以发现问题出现在use(router)这里
因为我们连路由前置守卫都没进去,就已经匹配路由了,动态路由还没添加,就肯定报错了
解决方法:https://blog.csdn.net/qq_37150410/article/details/128012829?fromshare=blogdetail&sharetype=blogdetail&sharerId=128012829&sharerefer=PC&sharesource=weixin_65363325&sharefrom=from_link
也是参考上面这位博主 的文章的方法,但是跟她的处理略有不同
上代码
在路由js文件,我把动态追加路由提取出来了
export async function initRouter(){ const userStore= useUserStore() await userStore.getUserInfo() let filterRouter = hasPermission(asyncRouter) filterRouter.push(cachAlll) // 添加动态路由 filterRouter.forEach((item) => { router.addRoute(item) }) // 打印动态路由以进行调试 console.log('动态路由:', filterRouter) console.log(router.getRoutes()) userStore.permissionRouter = [...routes, ...filterRouter] } router.beforeEach(async (to, from) => { console.log('路由前置守卫') const userStore = useUserStore() const token = userStore.token // 1.在白名单 if (whiteList.includes(to.path)) { return true } // 2.不在白名单 if (!whiteList.includes(to.path) && !token) { console.log('不在白名单') return '/login' } // 3.有token if (token) { // 3.1.判断有没有用户信息 if (JSON.stringify(userStore.userInfo) === '{}') { // 获取用户信息 await userStore.getUserInfo() } // 3.2.判断有没有权限路由 if (userStore.permissionRouter.length == 0) { await initRouter() } return true } })
复制
接下来是最重要的一步
main.js文件在注册router之前,强制初始化一下
async function initMainRouter() { await initRouter() app.use(ElementPlus, { locale: zhCn }) for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } app.use(createPinia()) app.use(router) console.log('入口文件2') app.mount('#app') } initMainRouter()
复制
使用await,强行让挂载等待路由初始化完成,彻底将刷新就空白页的问题解决。------引用上面博主文章的话,这个博主的口才真好
复制