Vue3 路由守卫详解:全局守卫、路由独享守卫、组件内守卫

一、前言

在Vue3开发中,路由守卫是一个非常重要的知识点。很多常见需求都离不开它,比如:

  • 页面权限控制

  • 登录校验

  • 动态路由参数校验

  • 页面离开提醒

  • 路由切换时执行额外逻辑

路由守卫本质上就是:在路由跳转的不同阶段,执行指定逻辑,对跳转过程进行控制。

本文重点整理三类最常用的守卫:

  • 全局路由守卫

  • 路由独享守卫

  • 组件内守卫

尽量聚焦在"是什么、怎么用、有什么作用"


二、什么是路由守卫

路由守卫可以理解为一种"拦截机制"。

当用户准备从一个页面跳转到另一个页面时,Vue Router 会在跳转前、跳转后,或者组件更新过程中,给我们一些可以插入逻辑的时机。我们可以在这些时机中:

  • 放行跳转

  • 拦截跳转

  • 重定向到其他页面

  • 执行提示、日志、校验等逻辑

简单说,路由守卫解决的是:

页面不是想进就进,也不是想走就走,而是先经过规则判断。


三、路由守卫的分类

Vue Router 中常见的路由守卫主要有三类:

1. 全局守卫

对所有路由都生效,适合处理整个项目通用的逻辑。

2. 路由独享守卫

只对某一个具体路由生效,适合处理该路由特有的逻辑。

3. 组件内守卫

写在页面组件内部,适合处理和当前组件强相关的逻辑。

可以先记住一句话:

全局守卫管整体,独享守卫管单个路由,组件内守卫管当前页面组件。


四、全局路由守卫

1. 什么是全局前置守卫

全局前置守卫会在每次路由跳转前执行,常用写法如下:

TypeScript 复制代码
router.beforeEach((to, from, next) => {
  next()
})

参数说明:

  • to:准备进入的目标路由

  • from:当前离开的路由

  • next:控制是否继续跳转

它最常见的作用就是:

  • 登录校验

  • 权限控制

  • 根据路由信息做统一判断


2. 全局前置守卫的典型用法

一个很常见的场景是:某些页面必须登录后才能访问。

示例:

TypeScript 复制代码
router.beforeEach((to, from, next) => {
  if (to.meta.login) {
    const token = localStorage.getItem('token')
    if (!token) {
      next('/login')
      return
    }
  }
  next()
})

这段代码的逻辑是:

  1. 每次跳转前先进入守卫

  2. 判断目标路由是否需要登录

  3. 如果需要登录,就去本地检查token

  4. 没有token就跳转到登录页

  5. 有token就正常放行

这里的重点不是代码本身,而是理解这种设计思路:

把通用的权限判断统一放到全局前置守卫里处理。


3.meta的作用

在做权限控制时,通常会结合路由元信息meta一起使用,例如:

TypeScript 复制代码
{
  path: '/admin',
  name: 'admin',
  component: Admin,
  meta: {
    login: true,
    title: '后台管理'
  }
}

这里的meta 可以理解为:给路由额外附加的自定义信息。

例如:

  • login:true 表示这个页面需要登录

  • title:可以用来设置页面标题

好处是:

  • 规则和路由配置写在一起,结构清晰

  • 全局守卫可以统一读取这些信息

  • 后期扩展角色权限也比较方便


4. 全局后置守卫

全局后置守卫会在路由跳转完成后执行,写法如下:

TypeScript 复制代码
router.afterEach((to, from) => {
  console.log('路由跳转完成')
})

它的常见用途有:

  • 记录日志

  • 页面埋点统计

  • 修改文档标题

注意两点:

  • afterEach没有next

  • 它不能阻止跳转

所以它更适合做"跳转完成之后的附加处理"。


五、路由独享守卫

1. 什么是路由独享守卫

路由独享守卫是只对某个路由生效的守卫,直接写在路由配置对象中,常用写法如下:

TypeScript 复制代码
{
  path: '/article/:id',
  name: 'article',
  component: Article,
  beforeEnter(to, from, next) {
    next()
  }
}

它适合处理某一个页面自己的进入规则,而不是整个项目的通用规则。


2. 路由独享守卫的典型作用

最常见的用途之一就是:进入页面前先校验路由参数。

例如文章详情页通常会写成:

TypeScript 复制代码
{
  path: '/article/:id',
  name: 'article',
  component: Article,
  beforeEnter(to, from, next) {
    const id = Number(to.params.id)
​
    if (isNaN(id)) {
      next(from)
      return
    }
​
    next()
  }
}

这里的意思是:

  • id本来应该是数字

  • 如果用户手动输入了错误地址,比如/article/xxx

  • 那么就不让它正常进入详情页

这就是路由独享守卫非常典型的使用方式:

只为某一个路由,增加进入前的专属校验。


3. 为什么这里不用全局守卫

因为这个参数校验只对文章详情页有效,不适用于其他页面。

如果强行写到全局守卫里,会带来两个问题:

  • 逻辑变杂,职责不清

  • 其他页面也会无意义地经过这段判断

所以这类"只属于某个页面"的规则,更适合写在 beforeEnter 中。


六、组件内守卫

组件内守卫写在页面组件内部,适合处理和当前页面组件密切相关的逻辑。

Vue Router里比较常见的两个组合式 API 写法是:

  • onBeforeRouteUpdate

  • onBeforeRouteLeave


1. onBeforeUpdate的作用

它会在当前路由更新,但组件被复用时触发。

示例:

TypeScript 复制代码
import { onBeforeRouteUpdate } from 'vue-router'
​
onBeforeRouteUpdate((to, from, next) => {
  console.log('路由参数变化时触发')
  next()
})

这个守卫特别适合详情页场景。

比如当前在:

TypeScript 复制代码
/article/1

然后跳转到:

TypeScript 复制代码
/article/2

这时很多情况下并不会重新创建一个新组件,而是复用原来的组件实例。也就是说,虽然地址变了,但页面组件还是同一个。

这时候如果你只在组件初次加载时处理数据,很可能拿不到更新后的参数,因此就需要 onBeforeRouteUpdate。

它的作用可以概括为:

  • 监听同一组件下的路由变化

  • 在参数变化时重新处理逻辑

  • 适合重新请求详情数据


2. onBeforeRouteLeave的作用

它会在当前组件对应的路由即将离开时触发。

示例:

TypeScript 复制代码
import { onBeforeRouteLeave } from 'vue-router'
​
onBeforeRouteLeave((to, from, next) => {
  console.log('路由离开时触发')
  next()
})

它常见的作用有:

  • 离开表单页前提醒用户

  • 未保存内容时阻止离开

  • 离开页面前做一些清理工作

例如:

TypeScript 复制代码
onBeforeRouteLeave((to, from, next) => {
  const leave = window.confirm('当前内容未保存,确定离开吗?')
  if (!leave) return
  next()
})

这类需求在后台管理系统和表单页面里非常常见。


七、三类守卫的区别总结

守卫类型 写在哪里 作用范围 常见用途
全局守卫 路由实例上 所有路由 登录校验、权限控制、埋点
路由独享守卫 单个路由配置中 当前路由 参数校验、页面准入
组件内守卫 页面组件内部 当前组件 参数变化、离开提醒

简而言之就是:

  • 通用规则,用全局守卫

  • 单页规则,用路由独享守卫

  • 页面内部行为,用组件内守卫


八、容易混淆的点

1. 不是所有逻辑都应该写到全局守卫里

全局守卫适合放"所有页面都可能会用到"的规则。 如果某段逻辑只对一个页面有效,就应该考虑写成路由独享守卫或组件内守卫。


2. 动态路由参数变了,不代表组件一定会重新创建

例如:

  • /article/1

  • /article/2

这两个地址看起来变了,但它们可能对应的仍然是同一个组件实例。


3. next()不能忘记

在使用这类守卫时,如果仍采用next这种写法,那么就必须正确调用它。

常见情况:

  • next():放行

  • next('/login'):重定向

  • 不调用:导航可能被卡住

所以写守卫时要有明确意识:到底是放行、拦截,还是跳去别的页面。


九、常见应用场景总结

1. 登录校验

适合用全局前置守卫。

2. 动态参数校验

适合用路由独享守卫。

3. 切换同类详情页重新加载数据

适合用组件内更新守卫。

4. 离开页面前提醒

适合用组件内离开守卫。

5. 页面跳转后记录日志

适合用全局后置守卫。


十、Review

1. 全局前置守卫

TypeScript 复制代码
router.beforeEach((to, from, next) => {
  next()
})

关键词:所有路由、进入前、统一控制

2. 全局后置守卫

TypeScript 复制代码
router.afterEach((to, from) => {})

关键词:跳转后、日志、埋点

3. 路由独享守卫

TypeScript 复制代码
beforeEnter(to, from, next) {
  next()
}

关键词:单个路由专属

4. 组件内更新守卫

TypeScript 复制代码
onBeforeRouteUpdate((to, from, next) => {
  next()
})

关键词:参数变化、组件复用

5. 组件内离开守卫

TypeScript 复制代码
onBeforeRouteLeave((to, from, next) => {
  next()
})

关键词:离开页面前确认


十一、总结

路由守卫的核心不是死记它的API,而是应该先理解"它解决什么问题":

  • 全局守卫解决通用规则问题

  • 路由独享守卫解决单一路由规则问题

  • 组件内守卫解决当前页面内部过程控制问题

把这三类守卫的定位分清楚,后面无论是做登录权限、详情页参数校验,还是页面离开提醒,都会更容易上手。

总而言之,就是:

先判断这是"全局问题、单页问题,还是组件内部问题",再决定用哪一种守卫。

相关推荐
卸任18 小时前
Vibe coding工具使用心得
前端·ai编程
brien919 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance19 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M19 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写19 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李19 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易20 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding20 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马20 小时前
前沿视界
前端
kyriewen20 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员