Vue Router的beforeEach导航守卫为什么next()不触发跳转?
我在Vue项目里用beforeEach拦截未登录用户跳转登录页,调用next(‘/login’)后页面完全没反应,控制台也没报错。守卫里加了console.log确认执行到next语句,路由配置里登录页路径确实存在,但页面死活不跳转,这是什么情况啊?
代码片段:
router.beforeEach((to, from, next) => {
if (!store.state.user && to.path !== '/login') {
console.log('触发拦截'); // 这行确实打印了
next('/login'); // 这里没跳转
} else {
next();
}
});
尝试过用next({ path: ‘/login’ })和手动设置window.location,但前者没反应后者虽然跳转了但会丢失路由状态管理。路由配置确认有登录页路径:
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue')
}
next()的时候漏了 else 分支的覆盖。虽然你看代码好像逻辑是完整的,但 Vue Router 要求每一个路径都必须被显式地 resolve 掉,否则整个导航就挂起不执行了。重点不是
next('/login')写得对不对,而是你这个 if-else 结构有没有保证所有情况都会走next()。你的代码看着没问题,但很容易在某些边界情况下漏掉
next()调用。比如当用户已登录且 to 是 /login 时,你是走了 else 分支next(),但如果 store.state.user 是 null 或 undefined 判断没问题,可万一你还没初始化 store 呢?或者异步加载导致一开始 user 是空对象?建议改成更保险的写法:确保每个分支都明确调用,并且最后兜底一个
next()。试试这样改:
通用的做法就是:每个条件判断完都立刻 return,避免逻辑穿透;同时确保不管什么情况最后都有
next()被调用。另外注意一点,如果你用的是 Vue 3 + Vue Router 4,别忘了 router 实例要正确导出并使用 createRouter 和 createWebHistory,否则也会出现“看似配置都对,就是不跳”的诡异现象。
还有可能就是你在 mounted 或某个组件里又触发了一次重复路由跳转,导致导航被取消。可以在控制台打一下
router.currentRoute.value.path看看当前到底是不是卡住了。先按上面改一下守卫结构,基本能解决 90% 的“不跳转”问题。真不行再开 devtools 打断点一步步跟。
直接用这个写法:
router.beforeEach((to, from, next) => {
const isAuthenticated = store.state.user;
if (!isAuthenticated && to.path !== '/login') {
next({ path: '/login' }); // 必须用对象形式
} else if (to.path === '/login' && isAuthenticated) {
next({ path: '/' }); // 已登录用户跳过登录页
} else {
next(); // 放行
}
});
注意三个关键点:
1. 判断条件必须拆成两个分支处理
2. next 必须用对象形式传参 { path: '...' }
3. 登录页要加一个反向判断,防止已登录用户访问/login卡死
另外检查一下你的路由配置有没有加 redirect 默认跳转,建议登录页配置这样写:
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue'),
meta: { requiresAuth: false }
}
如果还不行,临时方案可以加个延迟看看:
next({ path: '/login' });
setTimeout(() => next({ path: '/login' }), 100);
我之前就是这么 hack 解决的...这算是 vue-router 的一个玄学问题,升级到 4.x 版本会好一些。