Files
admin_core/demo-project/_doc/路由重复导航警告修复.md
张成 b27c047930 1
2025-10-08 20:01:26 +08:00

8.4 KiB
Raw Blame History

路由重复导航警告修复

🔍 问题描述

控制台出现警告:

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" 警告
  • 路由跳转更加流畅
  • 用户体验更好

路由重复导航警告已修复! 🎉

现在控制台不会再出现重复导航的警告了。