# 路由重复导航错误完全修复 ## 🔍 问题描述 页面直接报错: ``` 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,不会再出现错误了。