Files
admin_core/demo-project/路由重复导航错误完全修复.md
张成 99f73eff84 1
2025-10-08 19:30:09 +08:00

484 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 路由重复导航错误完全修复
## 🔍 问题描述
页面直接报错:
```
ERROR
Avoided redundant navigation to current location: "/home".
NavigationDuplicated: Avoided redundant navigation to current location: "/home".
at HashHistory.push
at VueComponent.turnToPage (main.vue:108:20)
```
## 📋 问题原因
### 错误来源
错误来自 `src/components/main/main.vue` 的两个方法:
**1. `goHome()` 方法**
```javascript
goHome() {
this.$router.push({ path: '/' }) // ❌ 如果已在首页,会报错
}
```
**2. `turnToPage()` 方法**
```javascript
turnToPage(route) {
// ...
this.$router.push({
name,
params,
query
}) // ❌ 如果跳转到当前页面,会报错
}
```
### 触发场景
**场景 1点击 Logo 回到首页**
```
当前页面: /home
点击 Logo
调用 goHome()
执行 this.$router.push({ path: '/' })
❌ 错误:已经在首页,重复导航
```
**场景 2点击当前激活的菜单**
```
当前页面: /home
点击"首页"菜单
调用 turnToPage({ name: 'home' })
执行 this.$router.push({ name: 'home' })
❌ 错误:已经在首页,重复导航
```
**场景 3刷新页面后点击菜单**
```
刷新页面
当前路由: /home
菜单激活状态: home
点击"首页"菜单
❌ 错误:重复导航
```
### Vue Router 的行为
**Vue Router 2.x/3.x**
- `router.push()` 返回一个 Promise
- 如果导航到当前路由,会抛出 `NavigationDuplicated` 错误
- 这个错误会导致页面崩溃(如果没有捕获)
## ✅ 解决方案
### 方案 1在跳转前检查是否是当前路由推荐
**优点**
- 避免不必要的路由跳转
- 性能更好
- 代码更清晰
**缺点**
- 需要在每个跳转方法中添加检查
### 方案 2捕获 Promise 错误
**优点**
- 代码简单
- 统一处理错误
**缺点**
- 仍然会触发路由跳转逻辑
- 性能稍差
### 方案 3结合使用本次采用
**优点**
- 既避免不必要的跳转
- 又捕获可能的错误
- 最稳健的方案
## 📝 修改内容
### 修改 `goHome()` 方法
**修改前**
```javascript
goHome() {
this.$router.push({ path: '/' }) // ❌ 可能重复导航
}
```
**修改后**
```javascript
goHome() {
// 避免重复导航到当前页面
if (this.$route.path !== '/' && this.$route.path !== '/home') {
this.$router.push({ path: '/' }).catch(err => {
// 忽略重复导航错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
}
```
**改进点**
- ✅ 检查当前路由是否是 `/``/home`
- ✅ 只在不是首页时才跳转
- ✅ 捕获并忽略重复导航错误
- ✅ 其他错误仍然会打印到控制台
### 修改 `turnToPage()` 方法
**修改前**
```javascript
turnToPage(route) {
let { name, params, query } = {}
if (typeof route === 'string') name = route
else {
name = route.name
params = route.params
query = route.query
}
if (name.indexOf('isTurnByHref_') > -1) {
window.open(name.split('_')[1])
return
}
this.$router.push({
name,
params,
query
}) // ❌ 可能重复导航
}
```
**修改后**
```javascript
turnToPage(route) {
let { name, params, query } = {}
if (typeof route === 'string') name = route
else {
name = route.name
params = route.params
query = route.query
}
if (name.indexOf('isTurnByHref_') > -1) {
window.open(name.split('_')[1])
return
}
// 避免重复导航到当前页面
if (this.$route.name === name) {
return
}
this.$router.push({
name,
params,
query
}).catch(err => {
// 忽略重复导航错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
```
**改进点**
- ✅ 检查目标路由是否是当前路由
- ✅ 如果是当前路由,直接返回,不跳转
- ✅ 捕获并忽略重复导航错误
- ✅ 其他错误仍然会打印到控制台
## 📊 修复后的流程
### 场景 1在首页点击 Logo
```
当前路由: /home
点击 Logo
调用 goHome()
检查: this.$route.path === '/home' ✅
直接返回,不跳转 ✅
✅ 没有错误
```
### 场景 2在其他页面点击 Logo
```
当前路由: /system/user
点击 Logo
调用 goHome()
检查: this.$route.path !== '/' && this.$route.path !== '/home' ✅
执行跳转: this.$router.push({ path: '/' })
跳转到首页 ✅
✅ 正常跳转
```
### 场景 3点击当前激活的菜单
```
当前路由: /home (name: 'home')
点击"首页"菜单
调用 turnToPage({ name: 'home' })
检查: this.$route.name === 'home' ✅
直接返回,不跳转 ✅
✅ 没有错误
```
### 场景 4点击其他菜单
```
当前路由: /home (name: 'home')
点击"用户管理"菜单
调用 turnToPage({ name: 'sys_user' })
检查: this.$route.name !== 'sys_user' ✅
执行跳转: this.$router.push({ name: 'sys_user' })
跳转到用户管理页面 ✅
✅ 正常跳转
```
## 🎯 关键点说明
### 1. 为什么要检查两个路径?
```javascript
if (this.$route.path !== '/' && this.$route.path !== '/home') {
// 跳转
}
```
**原因**
- 主路由配置了 `redirect: '/home'`
- 访问 `/` 会重定向到 `/home`
- 所以需要检查两个路径
### 2. 为什么使用 `catch()` 捕获错误?
```javascript
this.$router.push({ path: '/' }).catch(err => {
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
```
**原因**
- `router.push()` 返回 Promise
- 重复导航会抛出 `NavigationDuplicated` 错误
- 如果不捕获,错误会导致页面崩溃
- 捕获后可以忽略重复导航错误,但保留其他错误的日志
### 3. 为什么检查 `err.name !== 'NavigationDuplicated'`
```javascript
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
```
**原因**
- 只忽略重复导航错误
- 其他错误(如路由不存在、权限错误等)仍然需要打印
- 方便调试和排查问题
### 4. 为什么在 `turnToPage` 中直接 `return`
```javascript
if (this.$route.name === name) {
return // 直接返回
}
```
**原因**
- 如果是当前路由,不需要跳转
- 直接返回可以避免不必要的路由操作
- 性能更好
## ✅ 验证清单
### 功能验证
- ✅ 在首页点击 Logo → 不跳转,没有错误
- ✅ 在其他页面点击 Logo → 跳转到首页
- ✅ 点击当前激活的菜单 → 不跳转,没有错误
- ✅ 点击其他菜单 → 正常跳转
- ✅ 刷新页面后点击菜单 → 正常工作
### 错误检查
- ✅ 控制台没有 "NavigationDuplicated" 错误
- ✅ 控制台没有 "Avoided redundant navigation" 警告
- ✅ 页面不会崩溃
### 边界情况
- ✅ 快速连续点击菜单 → 正常工作
- ✅ 快速连续点击 Logo → 正常工作
- ✅ 在不同页面之间快速切换 → 正常工作
## 💡 最佳实践
### 1. 路由跳转前检查目标路由
**推荐**
```javascript
if (this.$route.name !== targetName) {
this.$router.push({ name: targetName })
}
```
**不推荐**
```javascript
this.$router.push({ name: targetName }) // 可能重复导航
```
### 2. 捕获 Promise 错误
**推荐**
```javascript
this.$router.push({ name: targetName }).catch(err => {
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
```
**不推荐**
```javascript
this.$router.push({ name: targetName }) // 错误会导致页面崩溃
```
### 3. 结合使用检查和捕获
**推荐**
```javascript
if (this.$route.name !== targetName) {
this.$router.push({ name: targetName }).catch(err => {
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
```
**优点**
- 避免不必要的跳转
- 捕获可能的错误
- 最稳健的方案
## 🔧 相关代码
### 完整的 `goHome()` 方法
```javascript
goHome() {
// 避免重复导航到当前页面
if (this.$route.path !== '/' && this.$route.path !== '/home') {
this.$router.push({ path: '/' }).catch(err => {
// 忽略重复导航错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
}
```
### 完整的 `turnToPage()` 方法
```javascript
turnToPage(route) {
let { name, params, query } = {}
if (typeof route === 'string') name = route
else {
name = route.name
params = route.params
query = route.query
}
if (name.indexOf('isTurnByHref_') > -1) {
window.open(name.split('_')[1])
return
}
// 避免重复导航到当前页面
if (this.$route.name === name) {
return
}
this.$router.push({
name,
params,
query
}).catch(err => {
// 忽略重复导航错误
if (err.name !== 'NavigationDuplicated') {
console.error(err)
}
})
}
```
## 📝 总结
### 修改内容
- ✅ 修改了 `goHome()` 方法,添加路由检查和错误捕获
- ✅ 修改了 `turnToPage()` 方法,添加路由检查和错误捕获
- ✅ 避免了重复导航错误
- ✅ 保持了原有的业务逻辑
### 效果
- ✅ 消除了 "NavigationDuplicated" 错误
- ✅ 页面不会崩溃
- ✅ 路由跳转更加流畅
- ✅ 用户体验更好
---
**路由重复导航错误已完全修复!** 🎉
现在可以放心地点击菜单和 Logo不会再出现错误了。