解决动态路由刷新白屏问题
这个算是遗留比较久的问题了,以前做项目的时候也遇到过,今天总算找到了解决方法
问题描述
由于需要做后台的权限控制,权限菜单需要后端发送数据,前端按需生成对应选项卡,这样就需要用到动态路由了,以下是一个动态路由的例子
// //前置导航守卫
router.beforeEach((to, from, next) => {
// 判断token,menu是否为空
console.log(from.path + "=>" + to.path);
if (getToken() && getItem("adminInfo") && to.path == "/login") {
alert("您已登录!");
router.push("/homepage");
}
if ((!getToken() || !getItem("adminInfo")) && to.path != "/login") {
alert("未登录");
router.push("/login");
}
//当store.$state.menus.length没有初始化好的时候才需要执行
if (getToken() && getItem("adminInfo")) {
//循坏菜单对象(动态路由)
const menus = store.getMenus as NewMenu;
//遍历添加路由,遍历创建路由
for (let key in menus) {
//获取一级路由
const newRoutes: RouteRecordRaw = {
path: "/" + menus[key].name,
name: menus[key].name,
component: () => import("@/views/HomePage/HomePage.vue"),
children: [],
};
//遍历创建二级路由
for (let i = 0; i < menus[key].children.length; i++) {
newRoutes.children?.push({
path: menus[key].children[i].name,
name: menus[key].children[i].name,
component: () =>
import(
`@/views/${menus[key].name}/${menus[key].children[i].name}.vue`
),
});
}
//添加路由到全局
router.addRoute(newRoutes);
}
console.log(router.getRoutes());
console.log(menus, "router-menus");
} else {
next();
}
});
以上是一个简单的路由守卫钩子,他负责路由鉴权以及动态生成路由,使用了localStorage存储菜单数据,pinia存储处理后的菜单数据,看上去没有问题,实则第一次点击确实可以进入路由,但是刷新后就会白屏
控制台显示:[Vue Router warn]: No match found for location with path "/pms/product"
解决方法
只需要在动态生成路由的功能入口判断一下store的menu是否已经就绪,然后在里面重定向一下当前路由next(to.path);
由于第二次进入路由守卫时menus已经准备就绪,所以就直接执行next()指令
//当store.$state.menus.length没有初始化好的时候才需要执行
if (getToken() && getItem("adminInfo") && store.$state.menus.length == 0) {
/*.......*/
//防止白屏,因为next的时候其实动态路由并没有初始化好,所以还需要to.path执行一次路由守卫
next(to.path);
} else {
next();
}
这样就解决了刷新白屏的问题,但是控制台的警告依旧存在...
这是因为第一次进入路由的时候,动态路由是在默认路由之后才执行的,所以警告会首先触发,我们可以通过添加一个通配符路由捕获掉第一次 ”不存在“ 的路由信息:
const routes: Array<RouteRecordRaw> = [
/*......*/
//添加一个全局路由用于捕获不存在的页面
{
path:'/:404(.*)',//404是我自己定义的名字,当然你也可以定义其他值
component:()=>import('@/views/404.vue')
}]