Vue 路由守卫怎么用:三种常用方式一次讲清

编程狮(w3cschool.cn) 2026-09-07 10:32:11 浏览数 (29)
反馈

你给后台系统加完页面,发现没登录的人直接敲地址就能进;复制链接发给同事,对方一打开就看到满屏数据。Vue 路由守卫就是专门拦在路由跳转路上的"门卫",它能在页面切换前做校验、改目标、甚至直接拦截。本文把全局前置守卫、路由独享守卫、组件内守卫三种常用方式一次讲清,并用最常见的登录鉴权场景串起来,照着写你就能把权限关进路由里。今天这篇文章,编程狮就用最通俗的讲法把它拆透。

Vue 路由守卫怎么用:三种常用方式一次讲清封面图

一、vue 路由守卫到底解决了什么问题

vue 路由守卫,本质上是 Vue Router 提供的一组"钩子函数":当路由准备跳转、正在跳转、或跳转完成时,框架会依次回调你注册的回调函数,你可以在这些回调里决定"放不放行"。如果不了解这套机制,新手往往会把权限判断写在每个组件的 mounted 里,结果入口分散、容易漏、还重复。

举个生活里的比喻:路由守卫就像公司前台。访客(路由)要进不同办公室(页面),前台先查工牌(登录态),没牌的引导去登记处(登录页),有牌但没权限的拦在门外。统一在前台处理,比每个房间自己装锁省心得多。

实际项目里,路由守卫解决的问题主要有三类。第一是登录鉴权:未登录访问受保护页面时,自动跳转到登录页。第二是权限分级:同样是登录用户,普通成员和管理员能进的页面不同。第三是离开确认:用户在表单页填了一半想关掉,弹出"确定离开吗"防止误删数据。

如果你对 Vue 的整体概念还不熟,建议先过一遍 Vue.js 基础教程,把组件、实例、响应式这些地基打牢,再回来理解守卫会轻松很多。理解了"守卫即钩子"这个核心,后面三种写法只是注册位置不同而已。

二、全局前置守卫 beforeEach 拦截未登录访问

全局前置守卫用 router.beforeEach 注册,它对所有路由跳转都生效,是做登录鉴权最常用的一处。它的回调函数接收三个参数:to(目标路由)、from(来源路由)、next(是否放行的控制函数,Vue Router 4 里也可以直接 return 一个结果来替代 next)。

最典型的写法,是给需要保护的路由在 meta 里标记 requiresAuth: true,然后在 beforeEach 里判断。下面是一段可直接运行的示例:

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  { path: '/', name: 'Home', component: Home },
  {
    path: '/dashboard',
    name: 'Dashboard',
    component: () => import('../views/Dashboard.vue'),
    meta: { requiresAuth: true, title: '编程狮 | w3cschool 后台' }
  },
  { path: '/login', name: 'Login', component: () => import('../views/Login.vue') }
]

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

router.beforeEach((to, from) => {
  const isLogin = localStorage.getItem('token')
  if (to.meta.requiresAuth && !isLogin) {
    return { name: 'Login', query: { redirect: to.fullPath } }
  }
  if (to.meta.title) {
    document.title = to.meta.title
  }
})

export default router

这段逻辑先读取本地 token 判断登录态;若目标路由要求鉴权却没有 token,就 return 一个登录页路由,并顺手带上 redirect 参数,方便登录后跳回原页面。注意 Vue Router 4 推荐"直接 return 目标"或 return false 取消导航,比老版本的 next() 更不容易写出死循环。

💡 小提示:把鉴权判断集中放在 beforeEach,比在每个页面里各自判断要清晰得多,也避免了"漏掉某个页面没加锁"的低级 bug。

三、路由独享守卫 beforeEnter 守护单条路由

有些页面比较特殊,只想对自己做校验,不想走全局守卫那套统一逻辑,这时可以用 beforeEnter。它直接写在路由配置项里,只对这一条路由生效,语法和 beforeEach 的回调几乎一样。

比如某个付费课程详情页,只要求访客来自特定渠道,用 beforeEnter 最合适:

// router/course.js
const routes = [
  {
    path: '/course/:id',
    name: 'CourseDetail',
    component: () => import('../views/CourseDetail.vue'),
    beforeEnter: (to, from) => {
      const allowed = ['weixin', 'app']
      if (!allowed.includes(to.query.from)) {
        return { name: 'Home' }
      }
    }
  }
]

export default routes

这里读取地址里的 from 参数,不是白名单渠道就直接打回首页。它和全局守卫的区别在于:beforeEach 管"所有路",beforeEnter 只管"这一条路",职责更聚焦,也方便把某条路由的校验逻辑就近放在它的配置旁边,可读性更好。

想系统学 Vue3 的新语法和路由写法,Vue3 官方教程 里的路由章节讲得更系统,适合边看边对照本项目改造。独享守卫用得不多,但一旦遇到"局部特殊规则",它就是最干净的解法。

四、组件内守卫控制页面进出时机

前两种守卫都注册在路由层面,而组件内守卫写在页面组件里,能感知"这个组件自身"的生命周期。它有三个钩子:onBeforeRouteEnter(进入前)、onBeforeRouteUpdate(同组件复用、参数变化时)、onBeforeRouteLeave(离开前)。

最实用的场景是离开确认。用户在表单页填了内容却没保存,这时直接点别的链接走了,数据就丢了。用 onBeforeRouteLeave 拦截最稳妥:

<script setup>
import { ref, onBeforeRouteLeave } from 'vue'

const draft = ref('')

onBeforeRouteLeave((to, from) => {
  if (draft.value.trim().length > 0) {
    const ok = window.confirm('内容还没保存,确定离开吗?')
    if (!ok) return false
  }
})
</script>

<template>
  <textarea v-model="draft" placeholder="在这里输入..."></textarea>
</template>

onBeforeRouteLeave 返回 false 就会取消这次跳转,用户得以留在页面;也可以用 return { name: 'xxx' } 改去别处。需要调用接口拿数据再决定是否放行时,onBeforeRouteEnter 还支持传 next 回调,等异步结果回来再决定。

组件内守卫的优势是上下文完整,能直接读到组件里的 refprops,不像路由层守卫还要绕一圈取数据。如果你的后台界面基于 Element Plus 搭建,Element Plus 教程 里的表单与消息提示组件能和这里的离开确认配合得很自然。

五、三种 vue 路由守卫怎么组合才不踩坑

三种 vue 路由守卫不是非此即彼,真实项目里常常组合使用:全局 beforeEach 兜底做统一登录鉴权,beforeEnter 处理个别页面的特殊规则,组件内守卫负责"离开前确认"这类和组件状态强相关的逻辑。分工清晰,才不会写出相互打架的判断。

最容易踩的坑有三个。第一,老版本里滥用 next() 导致重复导航或死循环;Vue Router 4 改用 return 返回值,能少写很多 bug。第二,把鉴权状态只存在内存里,页面一刷新就丢了,应当用 localStoragecookie 持久化 token。第三,忽略异步:beforeEach 里若要发请求验证 token 是否有效,必须等请求回来再 return,否则守卫会"放行得太快"。

⚠️ 注意:守卫里做权限判断只是前端层面的体验优化,真正的安全校验必须由后端接口完成。前端拦截挡不住有心人改代码绕过,绝不能把它当成安全防线。

调试时可以在每个守卫里 console.log(to, from) 打印路由对象,看清跳转链路。记住一条原则:越通用的规则越往全局放,越特殊的规则越往局部放,这样维护时一眼就能找到对应逻辑。当你能熟练把 vue 路由守卫按"全局—路由—组件"三层排布,权限与跳转就不再是难事。

Vue 三种路由守卫分别适用什么场景

总结

Vue 路由守卫是控制页面跳转的核心机制,本质是在路由切换的各个时机插入你的判断逻辑。回到家看本文开头的答案:它像前台门卫,统一拦在跳转路上做校验。

你应当带走的几个要点:全局 beforeEach 适合统一登录鉴权,路由级 beforeEnter 适合单条特殊规则,组件内守卫适合和组件状态绑定的进出控制;三者在项目里通常组合使用,越通用的越往全局放。下一步建议把本文示例接到你自己的路由文件里跑一遍,再补上后端接口校验,权限体系才算真正闭环。

延伸学习

想把这块知识系统补齐,可以按这个顺序来:

  1. 先跟着 Vue3 电商后台实战课程 把路由与鉴权放进真实后台项目里练手;
  2. 碰到路由基础概念模糊时,回看这篇 Vue Router 路由管理详解笔记 补充原理细节;
  3. 想顺手练前端工程化,可以用 前端 Bootstrap 项目实战 做几个页面巩固手感。

常见问题

Q:beforeEach 里用 next() 还是直接 return?

Vue Router 3 用 next() 系列,Vue Router 4 推荐直接 return 目标路由、return false 取消、或不返回表示放行。新项目优先用 return 写法,能避免 next 被漏调用或重复调用导致的死循环,代码也更直白。

Q:路由守卫能完全保证页面安全吗?

不能。守卫只是前端体验层拦截,用户改代码或绕过都能进到组件。真正的权限必须由后端接口校验:每次请求带 token,服务端确认有权才返回数据。前端守卫负责"少打扰",后端负责"真安全"。

Q:组件内守卫和路由守卫会重复触发吗?

会按固定顺序执行:先全局 beforeEach,再路由 beforeEnter,最后组件内 onBeforeRouteEnter。它们职责不同、互不替代。若逻辑重复,建议只保留最合适的一层,避免同一判断写两遍难以维护。

0 人点赞