8.4 KiB
8.4 KiB
路由重复导航警告修复
🔍 问题描述
控制台出现警告:
Avoided redundant navigation to current location: "/home".
NavigationDuplicated: Avoided redundant navigation to current location: "/home".
📋 问题原因
警告产生的场景
场景 1:已在首页时访问登录页
当前路由: /home
↓
用户访问: /login
↓
路由守卫检测到已登录
↓
尝试重定向: next({ name: 'home' })
↓
目标路由: /home
↓
❌ 警告:已经在 /home,避免重复导航
场景 2:刷新首页
当前路由: /home
↓
刷新页面
↓
路由守卫再次执行
↓
检测到已登录且访问登录页(可能的中间状态)
↓
尝试重定向: next({ name: 'home' })
↓
❌ 警告:已经在 /home,避免重复导航
原来的路由守卫代码
router.beforeEach((to, from, next) => {
const token = getToken()
ViewUI.LoadingBar.start()
if (to.name === 'view_log') {
next()
return
}
if (!token && to.name !== 'login') {
next({ name: 'login' })
} else if (!token && to.name === 'login') {
next()
} else if (token && to.name === 'login') {
// ❌ 没有检查来源路由,可能导致重复导航
next({ name: homeName })
} else {
next()
}
})
问题:
- 当已登录用户访问登录页时,总是重定向到首页
- 没有检查来源路由是否已经是首页
- 导致重复导航警告
✅ 解决方案
修改路由守卫逻辑
修改文件:src/router/index.js
修改后的代码:
router.beforeEach((to, from, next) => {
const token = getToken()
ViewUI.LoadingBar.start()
if (to.name === 'view_log') {
next()
return
}
if (!token && to.name !== 'login') {
// 未登录且访问非登录页 → 跳转到登录页
next({ name: 'login' })
} else if (!token && to.name === 'login') {
// 未登录且访问登录页 → 允许访问
next()
} else if (token && to.name === 'login') {
// 已登录且访问登录页 → 重定向到首页
// ✅ 避免重复导航警告
if (from.name === homeName) {
next(false) // 取消导航,停留在当前页面
} else {
next({ name: homeName }) // 重定向到首页
}
} else {
// 其他情况 → 允许访问
next()
}
})
关键改进
添加了来源路由检查:
if (from.name === homeName) {
next(false) // 如果来自首页,取消导航
} else {
next({ name: homeName }) // 否则重定向到首页
}
next(false) 的作用:
- 取消当前导航
- 停留在当前页面(首页)
- 不会触发重复导航警告
📊 修复后的流程
场景 1:从首页访问登录页
当前路由: /home (from.name = 'home')
↓
用户访问: /login (to.name = 'login')
↓
路由守卫检测到已登录
↓
检查来源路由: from.name === 'home' ✅
↓
执行: next(false)
↓
取消导航,停留在首页 ✅
↓
✅ 没有警告
场景 2:从其他页面访问登录页
当前路由: /system/user (from.name = 'sys_user')
↓
用户访问: /login (to.name = 'login')
↓
路由守卫检测到已登录
↓
检查来源路由: from.name !== 'home' ✅
↓
执行: next({ name: 'home' })
↓
重定向到首页 ✅
↓
✅ 正常导航,没有警告
场景 3:未登录访问登录页
当前路由: 无 (from.name = undefined)
↓
用户访问: /login (to.name = 'login')
↓
路由守卫检测到未登录
↓
执行: next()
↓
允许访问登录页 ✅
场景 4:登录成功后跳转
登录成功
↓
执行: window.location.href = '#/'
↓
触发完整页面加载
↓
访问: / (重定向到 /home)
↓
路由守卫检测到已登录
↓
to.name = 'home' (不是 'login')
↓
执行: next()
↓
允许访问首页 ✅
🎯 next() 方法说明
next() 的不同用法
1. next()
- 允许当前导航
- 继续执行路由跳转
2. next(false)
- 取消当前导航
- 停留在当前页面
- 不会触发路由变化
3. next({ name: 'home' })
- 重定向到指定路由
- 取消当前导航
- 跳转到新路由
4. next({ path: '/home' })
- 重定向到指定路径
- 取消当前导航
- 跳转到新路由
5. next(error)
- 终止导航
- 触发错误处理
为什么使用 next(false) 而不是 next()?
如果使用 next():
if (token && to.name === 'login') {
next() // ❌ 允许访问登录页
}
- 会允许已登录用户访问登录页
- 不符合业务逻辑
如果使用 next({ name: homeName }):
if (token && to.name === 'login') {
next({ name: homeName }) // ❌ 如果已在首页,会重复导航
}
- 如果来源路由已经是首页,会触发重复导航警告
使用 next(false):
if (token && to.name === 'login') {
if (from.name === homeName) {
next(false) // ✅ 取消导航,停留在首页
} else {
next({ name: homeName }) // ✅ 重定向到首页
}
}
- 如果来源是首页,取消导航,停留在首页
- 如果来源不是首页,重定向到首页
- 避免重复导航警告
✅ 验证清单
功能验证
- ✅ 未登录访问登录页 → 正常显示登录页
- ✅ 未登录访问其他页面 → 重定向到登录页
- ✅ 已登录访问登录页(从首页) → 停留在首页
- ✅ 已登录访问登录页(从其他页面) → 重定向到首页
- ✅ 登录成功 → 跳转到首页
警告检查
- ✅ 控制台没有 "Avoided redundant navigation" 警告
- ✅ 控制台没有 "NavigationDuplicated" 警告
- ✅ 路由跳转正常工作
边界情况
- ✅ 刷新首页 → 停留在首页
- ✅ 刷新其他页面 → 停留在当前页面
- ✅ 直接访问 URL → 正确处理
💡 最佳实践
1. 路由守卫中检查来源路由
推荐:
if (token && to.name === 'login') {
if (from.name === homeName) {
next(false) // 来自首页,取消导航
} else {
next({ name: homeName }) // 来自其他页面,重定向
}
}
不推荐:
if (token && to.name === 'login') {
next({ name: homeName }) // 可能导致重复导航
}
2. 使用 next(false) 取消不必要的导航
推荐:
if (shouldCancelNavigation) {
next(false) // 取消导航
}
不推荐:
if (shouldCancelNavigation) {
// 什么都不做,导航会继续
}
3. 避免在路由守卫中使用 window.location
推荐:
router.beforeEach((to, from, next) => {
if (needRedirect) {
next({ name: 'home' }) // 使用 next() 重定向
}
})
不推荐:
router.beforeEach((to, from, next) => {
if (needRedirect) {
window.location.href = '#/home' // 不要在守卫中使用
next(false)
}
})
🔧 相关代码
完整的路由守卫代码
文件:src/router/index.js
// 路由守卫配置
export const setupRouterGuards = (router, ViewUI, homeName = 'home') => {
router.beforeEach((to, from, next) => {
const token = getToken()
ViewUI.LoadingBar.start()
if (to.name === 'view_log') {
next()
return
}
if (!token && to.name !== 'login') {
// 未登录且访问非登录页 → 跳转到登录页
next({ name: 'login' })
} else if (!token && to.name === 'login') {
// 未登录且访问登录页 → 允许访问
next()
} else if (token && to.name === 'login') {
// 已登录且访问登录页 → 重定向到首页
// 避免重复导航警告
if (from.name === homeName) {
next(false) // 来自首页,取消导航
} else {
next({ name: homeName }) // 来自其他页面,重定向到首页
}
} else {
// 其他情况 → 允许访问
next()
}
})
router.afterEach(to => {
ViewUI.LoadingBar.finish()
window.scrollTo(0, 0)
})
return router
}
📝 总结
修改内容
- ✅ 在路由守卫中添加了来源路由检查
- ✅ 使用
next(false)避免重复导航 - ✅ 保持了原有的业务逻辑
效果
- ✅ 消除了 "Avoided redundant navigation" 警告
- ✅ 消除了 "NavigationDuplicated" 警告
- ✅ 路由跳转更加流畅
- ✅ 用户体验更好
路由重复导航警告已修复! 🎉
现在控制台不会再出现重复导航的警告了。