路由 守卫
2026/6/23 3:23:33 网站建设 项目流程

文章目录

  • 前言
  • 一、守卫类型概览
    • 1.1 三种守卫
    • 1.2 导航完整流程
  • 二、全局守卫
    • 2.1 beforeEach:全局前置守卫
    • 2.2 afterEach:全局后置守卫
    • 2.3 to / from 路由对象
  • 三、Vue Router 4 导航控制
    • 3.1 return 替代 next()
    • 3.2 return 值的含义
    • 3.3 异步守卫
  • 四、路由独享守卫
    • 4.1 beforeEnter
    • 4.2 与全局守卫的分工
  • 五、组件内守卫
    • 5.1 三个 Composition API 守卫
    • 5.2 onBeforeRouteLeave:离开确认
    • 5.3 onBeforeRouteUpdate:同组件参数变化
    • 5.4 onBeforeRouteEnter:组件未创建
  • 六、典型场景
    • 6.1 登录拦截 + 回跳
    • 6.2 动态页面标题
    • 6.3 NProgress 进度条
    • 6.4 编辑页离开确认(组合式封装)
  • 七、面试聚焦
    • 7.1 Vue Router 4 推荐 return 替代 next()
    • 7.2 onBeforeRouteEnter 能访问组件实例吗?
    • 7.3 多个守卫的执行顺序
  • 八、易混淆点
  • 九、思考与练习
  • 总结

前言

路由守卫是 Vue Router 在导航跳转各阶段提供的拦截机制,常用于登录校验、权限控制、离开确认等场景。本篇会讲清楚:

  • 全局守卫、路由独享守卫、组件内守卫
  • Vue Router 4 用return控制导航
  • 常见业务场景与完整示例

一、守卫类型概览

1.1 三种守卫

类型注册位置作用范围
全局守卫router.beforeEach/afterEach所有路由跳转
路由独享守卫路由配置beforeEnter单个路由
组件内守卫组件内onBeforeRouteXxx当前组件相关路由

1.2 导航完整流程

触发导航 ↓ beforeRouteLeave(离开的旧组件) ↓ beforeEach(全局前置) ↓ beforeEnter(目标路由独享) ↓ beforeRouteEnter(进入的新组件) ↓ 解析异步组件 / 执行路由组件守卫 ↓ beforeRouteUpdate(同一组件,路由参数变化) ↓ 导航确认 ↓ afterEach(全局后置) ↓ DOM 更新

二、全局守卫

2.1 beforeEach:全局前置守卫

// router/index.jsimport{createRouter,createWebHistory}from'vue-router'constrouter=createRouter({history:createWebHistory(),routes:[{path:'/login',component:()=>import('@/views/Login.vue')},{path:'/admin',component:()=>import('@/views/Admin.vue'),meta:{auth:true}}]})router.beforeEach((to,from)=>{consttoken=localStorage.getItem('token')// 需要登录但未登录 → 重定向if(to.meta.auth&&!token){return{path:'/login',query:{redirect:to.fullPath}}}})

2.2 afterEach:全局后置守卫

router.afterEach((to,from)=>{// 设置页面标题document.title=to.meta.title||'默认标题'// 页面访问埋点trackPageView(to.path)})

注意afterEach不接受return值,无法阻止或重定向导航,适合做副作用(标题、埋点、进度条结束)。

2.3 to / from 路由对象

router.beforeEach((to,from)=>{console.log(to.path)// '/user/1'console.log(to.params)// { id: '1' }console.log(to.query)// { tab: 'profile' }console.log(to.meta)// { auth: true, title: '用户' }console.log(to.fullPath)// '/user/1?tab=profile'console.log(to.name)// 'User'})

三、Vue Router 4 导航控制

3.1 return 替代 next()

Vue Router 3 使用next()回调,Vue Router 4 推荐通过返回值控制导航:

// ❌ Vue Router 3router.beforeEach((to,from,next)=>{if(!token)next('/login')elsenext()})// ✅ Vue Router 4router.beforeEach((to,from)=>{if(!token)return'/login'// 重定向// return false // 取消导航// return { name: 'Login' } // 命名路由重定向// return undefined / true // 放行(默认)})

3.2 return 值的含义

返回值效果
undefined/true放行,继续导航
false取消当前导航
路由路径字符串重定向到该路径
路由位置对象{ path, name, params, query }重定向到指定位置

3.3 异步守卫

router.beforeEach(async(to,from)=>{if(to.meta.auth){constisValid=awaitcheckToken()if(!isValid)return'/login'}})

守卫可以返回 Promise,Vue Router 会等待 Promise resolve 后再继续导航。


四、路由独享守卫

4.1 beforeEnter

仅对当前路由生效,在beforeEach之后、beforeRouteEnter之前执行。

constroutes=[{path:'/admin',component:()=>import('@/views/Admin.vue'),meta:{roles:['admin']},beforeEnter:(to,from)=>{constrole=localStorage.getItem('role')if(!to.meta.roles.includes(role)){return'/403'}}},{path:'/user/:id',component:()=>import('@/views/User.vue'),beforeEnter:(to,from)=>{// 校验 id 格式if(!/^\d+$/.test(to.params.id)){return'/404'}}}]

4.2 与全局守卫的分工

// 全局:登录态校验(所有需 auth 的路由)router.beforeEach((to,from)=>{if(to.meta.auth&&!token)return'/login'})// 独享:特定路由的角色/参数校验{path:'/admin',beforeEnter:(to,from)=>{if(role!=='admin')return'/403'}}

五、组件内守卫

5.1 三个 Composition API 守卫

import{onBeforeRouteEnter,onBeforeRouteUpdate,onBeforeRouteLeave}from'vue-router'
守卫触发时机
onBeforeRouteEnter进入该组件对应路由前(组件尚未创建)
onBeforeRouteUpdate路由变化但复用同一组件时(如/user/1/user/2
onBeforeRouteLeave离开该组件对应路由前

5.2 onBeforeRouteLeave:离开确认

<script setup> import { ref } from 'vue' import { onBeforeRouteLeave } from 'vue-router' const isDirty = ref(false) onBeforeRouteLeave((to, from) => { if (isDirty.value) { const answer = window.confirm('有未保存的修改,确定离开?') if (!answer) return false // 取消导航 } }) </script>

5.3 onBeforeRouteUpdate:同组件参数变化

<script setup> import { onBeforeRouteUpdate } from 'vue-router' const fetchUser = async (id) => { /* ... */ } onBeforeRouteUpdate(async (to, from) => { // /user/1 → /user/2,组件复用,需重新拉数据 await fetchUser(to.params.id) }) </script>

也可用watch(() => route.params.id, fetchUser)替代,效果类似。

5.4 onBeforeRouteEnter:组件未创建

<script setup> import { onBeforeRouteEnter } from 'vue-router' onBeforeRouteEnter((to, from) => { // ❌ 无法访问组件实例(组件尚未创建) // ❌ 无法使用 setup 中定义的 ref / 方法 // ✅ 可在进入前做数据预取 // return fetchUser(to.params.id) // 返回 Promise,导航会等待 }) </script>

Vue Router 4 变化:不再使用next(vm => ...)回调访问实例。进入后需在onMounted或通过watch route处理组件内逻辑。


六、典型场景

6.1 登录拦截 + 回跳

router.beforeEach((to,from)=>{consttoken=localStorage.getItem('token')if(to.path==='/login')returntrueif(to.meta.auth&&!token){return{path:'/login',query:{redirect:to.fullPath}}}})
// Login.vue 登录成功后constroute=useRoute()constrouter=useRouter()router.push(route.query.redirect||'/')

6.2 动态页面标题

router.afterEach((to)=>{document.title=to.meta.title?`${to.meta.title}- 我的应用`:'我的应用'})

6.3 NProgress 进度条

importNProgressfrom'nprogress'router.beforeEach(()=>{NProgress.start()})router.afterEach(()=>{NProgress.done()})

6.4 编辑页离开确认(组合式封装)

// composables/useLeaveConfirm.jsimport{ref}from'vue'import{onBeforeRouteLeave}from'vue-router'exportfunctionuseLeaveConfirm(){constisDirty=ref(false)onBeforeRouteLeave(()=>{if(isDirty.value){returnwindow.confirm('有未保存的修改,确定离开?')}})return{isDirty}}

七、面试聚焦

7.1 Vue Router 4 推荐 return 替代 next()

// VR4:return '/login' 重定向,return false 取消router.beforeEach((to,from)=>{if(!token)return'/login'})

7.2 onBeforeRouteEnter 能访问组件实例吗?

不能。组件尚未创建,无法访问 setup 中的 ref、methods。数据预取可返回 Promise;进入后的逻辑放在onMountedwatch route

7.3 多个守卫的执行顺序

离开旧组件 → 全局 beforeEach → 路由 beforeEnter → 进入新组件 beforeRouteEnter → beforeRouteUpdate → 全局 afterEach。

任一守卫return false或重定向,后续守卫按规则中断或转向新目标。


八、易混淆点

  1. afterEach 不能阻止导航:只做副作用,无return控制。
  2. onBeforeRouteEnter 无组件实例:Vue Router 4 已移除next(vm => ...),勿与 VR3 混用。
  3. 全局守卫按注册顺序执行:多个beforeEach依次执行。
  4. beforeRouteUpdate vs watch route:同组件参数变化时两者都可用;守卫在导航确认前执行,适合拦截;watch 适合响应式更新。
  5. meta 需主动配置:守卫里to.meta.auth要在路由配置中预先声明。

九、思考与练习

1.路由守卫有哪些类型?

解析:全局守卫(beforeEach / afterEach)、路由独享守卫(beforeEnter)、组件内守卫(onBeforeRouteEnter / Update / Leave)。

2.Vue Router 4 如何取消或重定向导航?

解析:return false取消;return '/path'return { name: 'Xxx' }重定向;不 return 或 return true 放行。

3.onBeforeRouteEnter 中为什么不能访问组件实例?

解析:守卫执行时组件尚未创建,setup 尚未运行,因此无法访问 ref、methods 等。

4.beforeEach 和 beforeEnter 如何分工?

解析:beforeEach 做全局通用逻辑(如登录态);beforeEnter 做单个路由特有校验(如角色权限、参数格式)。

5.如何实现编辑页离开时的未保存提示?

onBeforeRouteLeave(()=>{if(isDirty.value&&!confirm('确定离开?'))returnfalse})

总结

  • 三种守卫:全局、路由独享、组件内,在导航流程不同阶段拦截
  • Vue Router 4:用return控制导航,替代 Vue Router 3 的next()
  • 全局前置:登录校验、权限拦截;全局后置:标题、埋点、进度条
  • 组件内:Leave 做离开确认,Update 处理同组件参数变化,Enter 无法访问实例
  • 执行顺序:离开 → beforeEach → beforeEnter → Enter → Update → afterEach

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询