文章目录前言一、守卫类型概览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 beforeEnter4.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}fromvue-routerconstroutercreateRouter({history:createWebHistory(),routes:[{path:/login,component:()import(/views/Login.vue)},{path:/admin,component:()import(/views/Admin.vue),meta:{auth:true}}]})router.beforeEach((to,from){consttokenlocalStorage.getItem(token)// 需要登录但未登录 → 重定向if(to.meta.auth!token){return{path:/login,query:{redirect:to.fullPath}}}})2.2 afterEach全局后置守卫router.afterEach((to,from){// 设置页面标题document.titleto.meta.title||默认标题// 页面访问埋点trackPageView(to.path)})注意afterEach不接受return值无法阻止或重定向导航适合做副作用标题、埋点、进度条结束。2.3 to / from 路由对象router.beforeEach((to,from){console.log(to.path)// /user/1console.log(to.params)// { id: 1 }console.log(to.query)// { tab: profile }console.log(to.meta)// { auth: true, title: 用户 }console.log(to.fullPath)// /user/1?tabprofileconsole.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){constisValidawaitcheckToken()if(!isValid)return/login}})守卫可以返回 PromiseVue Router 会等待 Promise resolve 后再继续导航。四、路由独享守卫4.1 beforeEnter仅对当前路由生效在beforeEach之后、beforeRouteEnter之前执行。constroutes[{path:/admin,component:()import(/views/Admin.vue),meta:{roles:[admin]},beforeEnter:(to,from){constrolelocalStorage.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}fromvue-router守卫触发时机onBeforeRouteEnter进入该组件对应路由前组件尚未创建onBeforeRouteUpdate路由变化但复用同一组件时如/user/1→/user/2onBeforeRouteLeave离开该组件对应路由前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 // 取消导航 } }) /script5.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导航会等待 }) /scriptVue Router 4 变化不再使用next(vm ...)回调访问实例。进入后需在onMounted或通过watch route处理组件内逻辑。六、典型场景6.1 登录拦截 回跳router.beforeEach((to,from){consttokenlocalStorage.getItem(token)if(to.path/login)returntrueif(to.meta.auth!token){return{path:/login,query:{redirect:to.fullPath}}}})// Login.vue 登录成功后constrouteuseRoute()constrouteruseRouter()router.push(route.query.redirect||/)6.2 动态页面标题router.afterEach((to){document.titleto.meta.title?${to.meta.title}- 我的应用:我的应用})6.3 NProgress 进度条importNProgressfromnprogressrouter.beforeEach((){NProgress.start()})router.afterEach((){NProgress.done()})6.4 编辑页离开确认组合式封装// composables/useLeaveConfirm.jsimport{ref}fromvueimport{onBeforeRouteLeave}fromvue-routerexportfunctionuseLeaveConfirm(){constisDirtyref(false)onBeforeRouteLeave((){if(isDirty.value){returnwindow.confirm(有未保存的修改确定离开)}})return{isDirty}}七、面试聚焦7.1 Vue Router 4 推荐 return 替代 next()// VR4return /login 重定向return false 取消router.beforeEach((to,from){if(!token)return/login})7.2 onBeforeRouteEnter 能访问组件实例吗不能。组件尚未创建无法访问 setup 中的 ref、methods。数据预取可返回 Promise进入后的逻辑放在onMounted或watch route。7.3 多个守卫的执行顺序离开旧组件 → 全局 beforeEach → 路由 beforeEnter → 进入新组件 beforeRouteEnter → beforeRouteUpdate → 全局 afterEach。任一守卫return false或重定向后续守卫按规则中断或转向新目标。八、易混淆点afterEach 不能阻止导航只做副作用无return控制。onBeforeRouteEnter 无组件实例Vue Router 4 已移除next(vm ...)勿与 VR3 混用。全局守卫按注册顺序执行多个beforeEach依次执行。beforeRouteUpdate vs watch route同组件参数变化时两者都可用守卫在导航确认前执行适合拦截watch 适合响应式更新。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
路由 守卫
文章目录前言一、守卫类型概览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 beforeEnter4.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}fromvue-routerconstroutercreateRouter({history:createWebHistory(),routes:[{path:/login,component:()import(/views/Login.vue)},{path:/admin,component:()import(/views/Admin.vue),meta:{auth:true}}]})router.beforeEach((to,from){consttokenlocalStorage.getItem(token)// 需要登录但未登录 → 重定向if(to.meta.auth!token){return{path:/login,query:{redirect:to.fullPath}}}})2.2 afterEach全局后置守卫router.afterEach((to,from){// 设置页面标题document.titleto.meta.title||默认标题// 页面访问埋点trackPageView(to.path)})注意afterEach不接受return值无法阻止或重定向导航适合做副作用标题、埋点、进度条结束。2.3 to / from 路由对象router.beforeEach((to,from){console.log(to.path)// /user/1console.log(to.params)// { id: 1 }console.log(to.query)// { tab: profile }console.log(to.meta)// { auth: true, title: 用户 }console.log(to.fullPath)// /user/1?tabprofileconsole.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){constisValidawaitcheckToken()if(!isValid)return/login}})守卫可以返回 PromiseVue Router 会等待 Promise resolve 后再继续导航。四、路由独享守卫4.1 beforeEnter仅对当前路由生效在beforeEach之后、beforeRouteEnter之前执行。constroutes[{path:/admin,component:()import(/views/Admin.vue),meta:{roles:[admin]},beforeEnter:(to,from){constrolelocalStorage.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}fromvue-router守卫触发时机onBeforeRouteEnter进入该组件对应路由前组件尚未创建onBeforeRouteUpdate路由变化但复用同一组件时如/user/1→/user/2onBeforeRouteLeave离开该组件对应路由前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 // 取消导航 } }) /script5.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导航会等待 }) /scriptVue Router 4 变化不再使用next(vm ...)回调访问实例。进入后需在onMounted或通过watch route处理组件内逻辑。六、典型场景6.1 登录拦截 回跳router.beforeEach((to,from){consttokenlocalStorage.getItem(token)if(to.path/login)returntrueif(to.meta.auth!token){return{path:/login,query:{redirect:to.fullPath}}}})// Login.vue 登录成功后constrouteuseRoute()constrouteruseRouter()router.push(route.query.redirect||/)6.2 动态页面标题router.afterEach((to){document.titleto.meta.title?${to.meta.title}- 我的应用:我的应用})6.3 NProgress 进度条importNProgressfromnprogressrouter.beforeEach((){NProgress.start()})router.afterEach((){NProgress.done()})6.4 编辑页离开确认组合式封装// composables/useLeaveConfirm.jsimport{ref}fromvueimport{onBeforeRouteLeave}fromvue-routerexportfunctionuseLeaveConfirm(){constisDirtyref(false)onBeforeRouteLeave((){if(isDirty.value){returnwindow.confirm(有未保存的修改确定离开)}})return{isDirty}}七、面试聚焦7.1 Vue Router 4 推荐 return 替代 next()// VR4return /login 重定向return false 取消router.beforeEach((to,from){if(!token)return/login})7.2 onBeforeRouteEnter 能访问组件实例吗不能。组件尚未创建无法访问 setup 中的 ref、methods。数据预取可返回 Promise进入后的逻辑放在onMounted或watch route。7.3 多个守卫的执行顺序离开旧组件 → 全局 beforeEach → 路由 beforeEnter → 进入新组件 beforeRouteEnter → beforeRouteUpdate → 全局 afterEach。任一守卫return false或重定向后续守卫按规则中断或转向新目标。八、易混淆点afterEach 不能阻止导航只做副作用无return控制。onBeforeRouteEnter 无组件实例Vue Router 4 已移除next(vm ...)勿与 VR3 混用。全局守卫按注册顺序执行多个beforeEach依次执行。beforeRouteUpdate vs watch route同组件参数变化时两者都可用守卫在导航确认前执行适合拦截watch 适合响应式更新。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