文章目录

Vue 路由问题:路由守卫与导航

发布于 2026-04-04 02:01:22 · 浏览 2 次 · 评论 0 条

Vue 路由问题:路由守卫与导航

Vue Router 提供了“路由守卫”机制,用于在用户切换页面(即导航)时执行逻辑判断。你可以用它实现登录验证、权限控制、页面加载前的数据预取等功能。掌握路由守卫的使用方法,是构建健壮单页应用的关键一步。


一、理解三种路由守卫类型

Vue Router 的路由守卫分为三类,按执行顺序依次为:

  1. 全局守卫:作用于整个应用的所有路由跳转。
  2. 路由独享守卫:只对某个特定路由生效。
  3. 组件内守卫:写在具体组件内部,仅影响该组件的路由行为。

每种守卫都可在“进入前”、“更新时”或“离开后”触发,但最常用的是“进入前”的拦截逻辑。


二、配置全局前置守卫(最常用)

全局前置守卫 router.beforeEach 在每次路由跳转之前执行,适合做统一权限校验。

  1. 打开你的路由配置文件(通常是 src/router/index.jssrc/router.js)。
  2. 确保已创建 router 实例(通过 createRouter)。
  3. 调用 router.beforeEach 方法,并传入一个回调函数,该函数接收三个参数:to(目标路由)、from(来源路由)、next(继续导航的函数)。
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import Profile from '@/views/Profile.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/profile', component: Profile, meta: { requiresAuth: true } }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

router.beforeEach((to, from, next) => {
  const isAuthenticated = !!localStorage.getItem('token') // 简单判断是否登录
  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/') // 未登录且目标页需认证,则跳转首页
  } else {
    next() // 允许正常跳转
  }
})

export default router

关键点:

  • next() 必须被调用一次,否则导航会卡住。
  • 使用 meta 字段标记路由是否需要认证(如 meta: { requiresAuth: true }),这是一种约定俗成的做法。

三、设置路由独享守卫

如果你只想对某个路由做特殊处理,而不影响全局逻辑,可以使用路由独享守卫 beforeEnter

  1. 在路由定义中,为目标路由添加 beforeEnter 属性。
  2. 编写与全局守卫结构相同的回调函数。
const routes = [
  {
    path: '/admin',
    component: () => import('@/views/Admin.vue'),
    beforeEnter: (to, from, next) => {
      const userRole = localStorage.getItem('role')
      if (userRole === 'admin') {
        next()
      } else {
        next('/unauthorized')
      }
    }
  }
]

此守卫仅在进入 /admin 路径时触发,不影响其他页面。


四、使用组件内守卫

组件内守卫直接写在 Vue 组件中,适用于与组件强相关的导航逻辑(如离开页面前确认保存)。

  1. 在组件的 <script setup> 或选项式 API 中,定义以下三个可选的守卫函数:
    • beforeRouteEnter:进入该组件对应路由前调用(此时组件实例还未创建)。
    • beforeRouteUpdate:当前路由改变但组件复用时调用(如动态路由 /user/1/user/2)。
    • beforeRouteLeave:离开当前路由前调用。
<script setup>
import { onBeforeRouteLeave } from 'vue-router'

onBeforeRouteLeave((to, from, next) => {
  const answer = window.confirm('你有未保存的内容,确定要离开吗?')
  if (answer) {
    next()
  } else {
    next(false) // 取消导航
  }
})
</script>

<template>
  <div>编辑页面</div>
</template>

注意:在 <script setup> 中,需从 vue-router 导入对应的组合式函数;若使用选项式 API,则直接在组件对象中定义同名方法即可。


五、正确使用 next() 函数

next() 是控制导航流程的核心,不同调用方式产生不同效果:

调用方式 效果说明
next() 正常进入目标路由
next(false) 中断当前导航,留在原页面
next('/') 中断当前导航,重定向到指定路径
next({ name: 'Login' }) 通过命名路由跳转

务必避免在守卫中多次调用 next(),这会导致不可预期的行为。


六、处理异步逻辑(如 API 验证)

当守卫中需要发起网络请求(例如验证 token 是否有效),必须等待异步操作完成后再调用 next()

router.beforeEach(async (to, from, next) => {
  if (to.meta.requiresAuth) {
    try {
      const response = await fetch('/api/validate-token')
      if (response.ok) {
        next()
      } else {
        next('/login')
      }
    } catch (error) {
      next('/login')
    }
  } else {
    next()
  }
})

关键:将守卫回调声明为 async 函数,并用 await 等待结果,确保 next() 在异步完成后才被调用。


七、避免常见错误

  • 忘记调用 next():导致页面卡死,白屏无响应。
  • 在守卫中直接修改路由:不要在 beforeEach 里调用 router.push(),应使用 next('/path')
  • 滥用全局守卫:简单逻辑优先使用组件内守卫或路由独享守卫,保持全局逻辑简洁。
  • 忽略导航重复问题:如果 next() 传入的路径与当前路径相同,Vue Router 会抛出警告。可通过判断 to.path !== from.path 避免。

八、完整导航解析流程(文字描述)

当你触发一次路由跳转(如点击 <router-link> 或调用 router.push()),Vue Router 按以下顺序执行:

  1. 触发失活组件的 beforeRouteLeave 守卫。
  2. 调用全局 beforeEach 守卫。
  3. 触发目标路由的 beforeEnter 守卫(如果有)。
  4. 解析异步路由组件(如 () => import(...))。
  5. 触发新组件的 beforeRouteEnter 守卫。
  6. 导航被确认,更新 URL。
  7. 触发全局 afterEach 钩子(无 next,仅用于日志、埋点等)。
  8. 新组件实例创建完成,beforeRouteEnter 中可通过回调访问组件实例。

此流程确保了权限、数据、UI 更新的有序执行。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文