news 2026/3/16 13:46:28

【Vue Router 路由守卫(Navigation Guards)指南:概念、执行顺序、beforeResolve、异步路由组件】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Vue Router 路由守卫(Navigation Guards)指南:概念、执行顺序、beforeResolve、异步路由组件】

Vue Router 路由守卫(Navigation Guards)指南:概念、执行顺序、beforeResolve、异步路由组件

目标读者:有 Vue2/Vue3 项目经验、希望系统梳理 Vue Router 路由与守卫机制,能在实际工程协作与技术交流中解释清楚“为什么这样设计、怎么落地、有哪些边界与坑”。


目录

  • 1. 路由与导航的基本概念
  • 2. 路由守卫是什么:它解决了什么问题
  • 3. 守卫分类:为什么分全局、路由独享、组件内
  • 4. 固定导航流水线:执行顺序与“看起来不同”的原因
  • 5. beforeEach / beforeEnter / beforeResolve / afterEach:分别用来干什么
  • 6. 异步路由组件是什么:为什么影响导航阶段
  • 7. 典型案例与实践指南
  • 8. Vue Router 3 vs 4:API 差异与迁移注意点
  • 9. 常见坑点与排查清单
  • 10. 记忆化总结(要点速记版)
  • 术语表

1. 路由与导航的基本概念

1.1 路由(Route)是什么

  • 路由是一种URL → 页面/组件状态的映射规则。
  • 在 SPA 中,路由变化通常不会触发整页刷新,而是改变:
    • 当前要渲染的组件树
    • 组件接收的参数(params/query
    • 与页面相关的副作用(标题、埋点、数据加载等)

1.2 导航(Navigation)是什么

  • 导航是从一个路由状态from切换到另一个路由状态to的过程。
  • 导航不是“单纯切换组件”,而是一次可控的状态迁移:
    • 可能需要鉴权
    • 可能需要异步准备(加载路由组件/获取数据)
    • 可能需要阻止离开(未保存提示)

2. 路由守卫是什么:它解决了什么问题

2.1 定义

路由守卫(Navigation Guards)本质是:

  • 在一次导航的生命周期中插入可拦截、可异步、可重定向的钩子函数。
  • 它让你能在“导航发生前/中/后”执行控制逻辑。

2.2 为什么需要守卫(工程视角)

如果没有守卫,常见问题是:

  • 只能在组件mounted里做鉴权 →会闪屏(页面先渲染再被踢走)
  • 鉴权、动态路由注入逻辑分散在各页面 →重复、难维护
  • 导航过程涉及异步逻辑(权限、配置、远程菜单)→ 需要可等待的机制
  • 快速连续跳转会产生竞态 → 需要可取消/可重入的导航控制

3. 守卫分类:为什么分全局、路由独享、组件内

可以用“作用域(Scope)”来理解。

3.1 三类守卫分别是什么

分类作用域典型 API适用问题关键特点
全局守卫(Global)全站beforeEach/beforeResolve/afterEach全站统一规则:鉴权、动态路由、埋点、进度条一次配置,处处生效
路由独享守卫(Per-route)某条路由记录beforeEnter某模块门禁:只对 admin/finance 等模块跟着路由表走,集中管理
组件内守卫(In-component)某个组件实例beforeRouteLeave/Update/Enter与页面状态强相关:未保存离开、同组件复用刷新就近维护,贴近状态

3.2 为什么要这么区分(高分解释)

  • 责任边界清晰:应用策略、路由规则、页面状态各管各的
  • 复用成本最小化:能全局复用的不要散落到组件里
  • 降低耦合:路由层不依赖具体组件细节,组件也不承载全站策略
  • 执行顺序可控:先出门(leave),再过总闸(global),再过分闸(route),最后进屋(enter)

3.3 记忆口诀(作用域)

  • 全站 → 这条路 → 这个页面

4. 固定导航流水线:执行顺序与“看起来不同”的原因

重点:顺序不是“多种情况”,而是一条固定流水线在不同导航里有些步骤为空。

4.1 固定导航流水线(快速复述版)

一次导航从fromto,按照以下阶段执行(按语义理解即可):

  1. 离开阶段(Leave)
    • beforeRouteLeave(离开的组件里有才触发)
  2. 全局前置(Global before)
    • router.beforeEach
  3. 复用更新(Update)
    • beforeRouteUpdate(同组件复用、参数变化才触发)
  4. 路由门禁(Route before)
    • beforeEnter(目标路由有才触发)
  5. 解析阶段(Resolve / Components)
    • 解析匹配组件、加载异步路由组件(() => import()
    • 运行beforeRouteEnter(进入组件里有才触发)
  6. 全局解析后(Global resolve)
    • router.beforeResolve
  7. 导航完成(After)
    • router.afterEach

记忆化:先出门 → 过总闸 → 同屋更新 → 过分闸 → 拿钥匙进屋 → 总检 → 收尾

4.2 为什么有时看起来“顺序不同”

因为某些阶段根本不存在:

  • 没有离开确认 → 没有beforeRouteLeave
  • 不是同组件复用 → 没有beforeRouteUpdate
  • 目标路由没写beforeEnter→ 跳过
  • 目标路由组件不是异步 import → “解析阶段”很快,感觉不到
  • 组件没写beforeRouteEnter→ 进入阶段跳过

4.3 为什么是 “beforeRouteLeave → beforeEach”

  • 语义:先问“旧页面放不放你走”,再谈“全站策略让不让你去”
  • 避免副作用:如果beforeEach里会请求/埋点/开启 loading,用户最终取消离开会产生脏副作用
  • 体验:离开确认应该立即响应,不应等全局异步逻辑跑完

4.4 为什么是 “beforeEach → beforeRouteUpdate → beforeEnter”

  • beforeEach是总闸:先决定本次导航是否继续,避免无意义的实例级工作
  • beforeRouteUpdate依赖“匹配结果 + 复用判定 + 已存在组件实例”,因此在全局通过后收集执行
  • beforeEnter是目标路由记录门禁:在组件进入前保证复用组件已同步到新参数,避免状态交错

5. beforeEach / beforeEnter / beforeResolve / afterEach:分别用来干什么

5.1 beforeEach:全站总闸门

职责:对每一次导航执行统一前置逻辑,决定放行/取消/改道。

常见用途:

  • 登录鉴权(未登录 →/login
  • 动态路由注入(拉权限 →addRoute→ 重新进入)
  • 全局进度条开始(如NProgress.start()

5.2 beforeEnter:某条路由/某模块门禁

职责:只对特定模块/路由生效的门禁。

典型场景:

  • /admin模块需要管理员权限
  • 进入/tenant/*前必须选择租户

对比 beforeEach:

  • beforeEach适合“全站规则”,否则会变成一堆 if-else
  • beforeEnter适合“模块规则”,跟路由配置集中管理

5.3 beforeResolve:最后的全局兜底(总检)

一句话beforeResolve是导航确认前的最后一道全局前置检查。

它的价值在于:

  • 保证路由级守卫与组件相关解析流程(含异步组件)都已走到“接近 ready”的阶段
  • 适合做最终兜底:
    • 权限/配置最终检查
    • 最终确认 loading 是否应该结束
    • 动态路由注入后的 matched 校验

直觉理解:beforeEach是“进流程前的总闸”,beforeResolve是“进门前的总检”。

5.4 afterEach:导航完成后的收尾

关键限制afterEach不能拦截/重定向,只能做副作用。

典型用途:

  • PV 埋点(确认落地路由)
  • 更新标题、面包屑
  • 结束进度条(NProgress.done()

6. 异步路由组件是什么:为什么影响导航阶段

6.1 定义

异步路由组件是指路由组件用函数返回动态 import:

// Vue Router 3/4 均可constroutes=[{path:'/report',component:()=>import('@/pages/Report.vue'),},]

6.2 为什么要用(选型建议)

  • 路由组件通常体积大(图表、地图、编辑器、复杂表格)
  • 异步加载能实现按路由拆包(code splitting)
  • 目标:减少首包体积、加快首屏

6.3 为什么会影响守卫顺序

导航到/report时,必须先把Report.vue对应的 chunk 加载并解析,才能进入“渲染新页面”。这就是“解析阶段”的来源。

beforeResolve的设计目的之一:在异步组件与组件内守卫都处理到位后做最后兜底。


7. 典型案例与实践指南

7.1 案例:登录鉴权 + 白名单(beforeEach)

目标:未登录访问需要登录的页面 → 跳转登录;登录后回跳原页面。

Vue Router 4(推荐 return 风格)
// router/guard.tsrouter.beforeEach(async(to)=>{constisPublic=Boolean(to.meta.public)consttoken=auth.getToken()if(isPublic)returntrueif(!token){return{name:'login',query:{redirect:to.fullPath},}}returntrue})
Vue Router 3(next 风格)
router.beforeEach((to,from,next)=>{constisPublic=Boolean(to.meta.public)consttoken=auth.getToken()if(isPublic)returnnext()if(!token){returnnext({name:'login',query:{redirect:to.fullPath}})}next()})

最佳实践

  • beforeEach 里避免多次调用next()
  • 推荐用return(Router 4)减少分支错误

7.2 案例:动态路由注入(权限路由)

场景:登录后根据权限生成菜单与路由。第一次进入系统必须先拉权限,再 addRoute。

关键点:

  • 用 flag 避免重复注入
  • 注入完成后重新进入目标路由(通常next(to.fullPath)return to.fullPath
letroutesInited=falserouter.beforeEach(async(to)=>{consttoken=auth.getToken()if(!token)returnto.name==='login'?true:{name:'login'}if(!routesInited){constperms=awaitapi.getPermissions()constdynRoutes=buildRoutes(perms)dynRoutes.forEach(r=>router.addRoute(r))routesInited=true// 关键:重新进入,确保 matched 重新计算returnto.fullPath}returntrue})

7.3 案例:离开确认(beforeRouteLeave)

场景:编辑页未保存,离开提示确认。

exportdefault{data(){return{dirty:false}},beforeRouteLeave(to,from,next){if(!this.dirty)returnnext()constok=window.confirm('内容未保存,确定离开?')next(ok)},}

实践建议

  • 离开确认属于页面状态,放组件内最合适
  • 不要放全局 beforeEach(会污染全局逻辑)

7.4 案例:同组件复用刷新(beforeRouteUpdate)

场景:/user/1/user/2复用同一个详情组件。

exportdefault{asyncbeforeRouteUpdate(to,from,next){awaitthis.fetchDetail(to.params.id)next()},}

7.5 案例:路由 PV 埋点 + sendBeacon

结论
  • PV/路由到达事件:建议放router.afterEach(拿到最终落地路由,减少中途重定向脏数据)
  • 停留时长/退出上报:建议放pagehide/visibilitychange,并使用navigator.sendBeacon提高卸载场景成功率
路由 PV(afterEach)
router.afterEach((to,from)=>{analytics.track('page_view',{path:to.fullPath,referrer:from.fullPath,})})
退出/停留(pagehide + sendBeacon)
functionreportLeave(payload:any){consturl='/analytics/leave'constbody=JSON.stringify(payload)// sendBeacon 适合卸载场景navigator.sendBeacon?.(url,body)}window.addEventListener('pagehide',()=>{reportLeave({path:location.pathname,ts:Date.now(),})})document.addEventListener('visibilitychange',()=>{if(document.visibilityState==='hidden'){reportLeave({path:location.pathname,ts:Date.now(),})}})

最佳实践

  • sendBeacon不适合做所有请求;更适合“卸载/切后台”这类容易丢包的上报
  • afterEach 里更多是“到达页”事件;离开/停留要用 pagehide/visibilitychange

8. Vue Router 3 vs 4:API 差异与迁移注意点

对比项Vue Router 3(Vue2)Vue Router 4(Vue3)
控制导航next()推荐return true/false/routeLocation
异步守卫手动next()await更自然
常见坑next()多次/漏调return更不易写错

8.1 Router 4 的推荐写法(return 风格)

  • return true:放行
  • return false:取消
  • return { name: 'login' }:重定向

9. 常见坑点与排查清单

9.1 导航卡死

  • Vue Router 3:忘记next()/ 分支没返回
  • Vue Router 4:async 分支未return

9.2 next 调用两次(Router 3)

  • return next(...)保证单路径

9.3 重定向循环

  • 登录页也被鉴权拦截
  • 解决:白名单 /meta.public

9.4 动态路由注入后 404

  • addRoute后不重新进入
  • 解决:重新进入to.fullPath

9.5 组件复用导致数据不刷新

  • mounted不会重跑
  • beforeRouteUpdate/ watch route params

9.6 afterEach 里做鉴权

  • afterEach 不能拦截,只会产生“闪一下再跳”

9.7 sendBeacon 使用误区

  • afterEach 更适合 PV;退出类上报使用 pagehide/visibilitychange

10. 记忆化总结(要点速记版)

10.1 作用域口诀

  • 全站 → 这条路 → 这个页面

10.2 流水线口诀

  • 出门(leave)→ 总闸(beforeEach)→ 同屋更新(beforeRouteUpdate)→ 分闸(beforeEnter)→ 拿钥匙进屋(异步组件/enter)→ 总检(beforeResolve)→ 收尾(afterEach)

10.3 一分钟摘要

  • 路由守卫是导航生命周期中的拦截器链,支持异步、取消、重定向。
  • 按作用域分全局、路由独享、组件内,目的是清晰边界、降低耦合、提高复用。
  • 执行上是一条固定流水线,某些步骤在特定导航里不存在所以看起来不同。
  • beforeEach 做全站门禁,beforeEnter 做模块门禁,beforeResolve 做最后兜底,afterEach 做收尾埋点。
  • 异步路由组件通过() => import()实现按路由拆包,会引入解析阶段,因此 beforeResolve 在工程里很重要。

术语表

  • 导航(Navigation):一次从fromto的路由迁移过程。
  • 路由记录(Route Record):路由表中的一条配置(包含 path/component/meta/beforeEnter)。
  • 匹配(matched):当前路由匹配到的路由记录链条(父子嵌套)。
  • 异步路由组件:路由组件使用() => import()动态加载,实现按路由拆包。
  • PV(Page View):页面访问量统计,通常在 afterEach 记录“最终落地页”。
  • sendBeacon:浏览器提供的卸载期上报 API,适合页面离开时保证上报成功率。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/13 19:40:59

纯电动汽车仿真:从模型搭建到动力性与经济性分析

纯电动汽车仿真、纯电动公交、纯电动客车、纯电动汽车动力性仿真、经济性仿真。 模型包括电机、电池、车辆模型。 有两种模型2选1: 1 完全用matlab simulink搭建的模型。 2用simscape搭建的车辆模型。 项目开发使用的模型,精确度高,不是随便乱…

作者头像 李华
网站建设 2026/3/16 2:12:25

新能源控制器中多峰值MPPT寻优仿真模型探索

新能源控制器,多峰值mppt寻优仿真模型,传统扰动电导等寻优无法用在局部遮阴下,而粒子群pso算法克服了这个问题,可用于自行研究。 压缩包附带使用说明及解析文档,包括传统扰动与粒子群算法模型。在新能源领域&#xff0…

作者头像 李华
网站建设 2026/3/13 16:22:41

双向DC/DC磷酸铁锂蓄电池充放电储能的Matlab/Simulink仿真模型探索

双向DC/DC磷酸铁锂蓄电池充放电储能matlab/simulink仿真模型,采用双闭环控制,充放电电流,电压和功率均可控,电流为负则充电,电流为正则放电,可以控制电流实现充放电 (1)完整复现文献…

作者头像 李华
网站建设 2026/3/13 2:58:43

含多种需求响应及电动汽车的微网/虚拟电厂日前优化调度探索

含多种需求响应及电动汽车的微网/虚拟电厂日前优化调度3 关键词:需求响应 空调负荷 电动汽车 微网优化调度 虚拟电厂调度 参考文档:《计及电动汽车和需求响应的多类电力市场下虚拟电厂竞标模型》参考其电动汽车模型以及需求响应模型; 《S…

作者头像 李华
网站建设 2026/3/15 12:04:38

论文查重AI率工具排行榜:9大检测平台+标准推荐

论文查重AI率工具排行榜:9大检测平台标准推荐AI论文工具核心特点速览工具名称查重效率降重能力适用场景特色功能aicheck⚡⚡⚡⚡⚡⭐⭐⭐⭐高重复率论文快速降重专业术语保留率高aibiye⚡⚡⚡⚡⭐⭐⭐⭐⭐学术论文深度改写逻辑结构优化askpaper⚡⚡⚡⭐⭐⭐日常论文…

作者头像 李华
网站建设 2026/3/15 0:50:07

论文生成慢半拍?十大AI工具,AIGC降重+快速出初稿

论文生成慢半拍?十大AI工具,AIGC降重快速出初稿�� AI工具性能速览表工具名称核心功能处理时间AI生成率控制适配检测平台askpaper降AIGC率降重同步20分钟个位数知网/格子达/维普秒篇AI痕迹深度弱化20分钟个位数知网/格子达/维普aic…

作者头像 李华