当前位置: 首页 > news >正文

前端面经-VUE3篇(三)--vue Router(二)导航守卫、路由元信息、路由懒加载、动态路由

一、导航守卫

 vue Router 中的 导航守卫(Navigation Guards) 是一个非常重要的功能,用于在路由切换过程中,拦截、控制、检查或延迟页面跳转

你可以理解为:

🔐 “进门前的保安”,控制哪些页面可以进入,哪些要被拦下,甚至可以临时让你等一等(如加载数据)。

1、导航守卫是什么?

导航守卫 = 在页面跳转时运行的“钩子函数”,用于:

  • 登录验证(如没登录 → 拦住不让进)

  • 权限判断(普通用户不能进后台)

  • 加载数据(等异步数据加载完再跳转)

  • 保存草稿、弹窗确认(是否离开页面)

2、导航过程中的“六大守卫钩子”

1. 全局守卫(作用于整个路由系统)

全局守卫是指:在所有路由跳转时都会触发的拦截钩子函数,你可以在这里:

  • 检查权限(如登录验证)

  • 记录日志

  • 控制页面跳转流程

  • 加载全局资源

  • 拦截非法路径、错误跳转

1、 全局守卫的分类(3种)
守卫名称执行时机是否需要调用 next()
beforeEach跳转开始前✅ 是
beforeResolve所有组件守卫解析后✅ 是
afterEach跳转结束后❌ 否(只是通知)
 1.最常用的:router.beforeEach()
router.beforeEach((to, from, next) => {// to: 即将进入的路由// from: 当前离开的路由// next(): 控制是否放行
})

 示例:登录拦截

router.beforeEach((to, from, next) => {const isLogin = !!localStorage.getItem('token')if (to.meta.requiresAuth && !isLogin) {next('/login') // 没登录跳转登录页} else {next() // 放行}
})

next() 的几种用法

写法作用
next()允许正常跳转
next(false)中止导航(地址栏会回退)
next('/login')重定向到其他页面
next(new Error())抛出错误,触发全局错误捕获
2.beforeResolve()(较少使用)
router.beforeResolve((to, from, next) => {// 所有 beforeEach、组件 beforeRouteEnter、beforeEnter 都 resolve 后执行next()
})

用途:

  • 等待所有数据加载完再显示加载动画

  • 对所有守卫结果做最后决策

 3.afterEach()(无 next)
router.afterEach((to, from) => {// 跳转后做事情,如:sendAnalytics(to.path)
})
  • 不能拦截跳转,只是一个通知钩子

  • 用于记录操作、埋点统计、结束 loading 等

2、执行顺序图解

如果你从 /login 跳到 /dashboard

 → router.beforeEach()
→ 路由配置里的 beforeEnter(如果有)
→ 组件的 beforeRouteEnter(如果有)
→ router.beforeResolve()
→ 页面渲染
→ router.afterEach()

3、实际应用场景
场景使用钩子
登录状态拦截beforeEach
动态加载权限路由beforeEach
请求加载动画beforeResolve
页面跳转埋点统计afterEach
首次访问重定向beforeEach

2、 路由独享守卫(配置在某个路由项中)

1、什么是“路由独享守卫”?

路由独享守卫是定义在某一个路由配置项中的钩子函数,只在进入该路由时触发

📌 区别于全局守卫,它不会影响其他页面,适合只对特定路由做控制。

 语法格式

{path: '/admin',component: AdminPage,beforeEnter(to, from, next) {// 只会在进入 /admin 时触发if (isAdmin()) {next() // 放行} else {next('/no-access') // 重定向}}
}
2、典型用途场景
场景示例
后台路由权限拦截/admin 只有管理员能进
特定页面加载前校验数据/editor 页面检查草稿是否存在
临时页面的跳转控制/event/:id 检查活动是否开启
3、和全局守卫的区别
全局守卫路由独享守卫
触发时机所有路由跳转都触发只在进入某个特定页面时触发
代码位置路由实例中单个路由配置项中
使用场景登录检查、全站控制单页权限、页面特殊逻辑

示例:后台权限验证

const routes = [{path: '/admin',component: AdminView,beforeEnter(to, from, next) {const user = getUserInfo()if (user.role === 'admin') {next()} else {next('/403')}}}
]
4、注意事项
  • 如果你既使用了全局守卫又用了路由独享守卫,它们是串联执行的。

  • 路由独享守卫在组件还没创建时就执行,因此不能访问组件实例 this

 3. 组件内守卫(定义在组件中)

1、什么是组件内守卫?

组件内守卫是直接定义在组件内部的路由钩子函数,用于在“进入当前组件”、“更新当前组件参数”或“离开当前组件”时执行逻辑。

 它和全局守卫 / 路由独享守卫相比,更适用于组件内部逻辑控制,如弹窗提示、数据加载、组件状态管理等。

2、组件内三种守卫(使用时机)
守卫名触发时机常见用途
beforeRouteEnter即将进入组件前(组件还未创建)判断是否允许进入、等数据加载完
beforeRouteUpdate同组件但路由参数变化时响应式更新组件内容
beforeRouteLeave离开当前组件时弹窗确认、保存草稿

示例讲解

 1. beforeRouteEnter(to, from, next)

📌 组件还没创建,所以你不能访问 this

export default {beforeRouteEnter(to, from, next) {// 在进入该组件前执行console.log('准备进入这个组件')// 如果你需要访问组件实例,可以这样写:next(vm => {console.log('组件实例是:', vm)})}
}
2. beforeRouteUpdate(to, from, next)

📌 组件已经渲染,只是参数变了

常用于如 /user/1/user/2 的这种路径变化

export default {beforeRouteUpdate(to, from, next) {// 当 :id 参数变化时触发this.userId = to.params.idthis.fetchData()next()}
}
3.beforeRouteLeave(to, from, next)

📌 离开当前组件前触发

常用于弹窗确认:

export default {beforeRouteLeave(to, from, next) {if (this.formChanged) {const answer = window.confirm('你有未保存的更改,确定离开?')if (!answer) return next(false)}next() // 放行}
}
3、注意事项
  • beforeRouteEnter 无法访问 this,必须用 next(vm => {...}) 才能访问组件实例。

  • 如果你使用的是 <script setup>,这些守卫要通过 onBeforeRouteLeave() 等组合式 API 来注册。

3、守卫执行顺序图解

假设你从 /a/b,执行顺序是:

 1. 全局 beforeEach
2. 路由 beforeEnter
3. 组件 beforeRouteLeave(离开 a)
4. 组件 beforeRouteEnter(进入 b)
5. 全局 beforeResolve
6. 页面渲染
7. 全局 afterEach

4、常见坑点

错误用法正确说明
next() 忘记写会导致跳转永远卡住
beforeRouteEnter 中访问 this不行!因为组件还没被创建,用 next(vm => {...})
beforeRouteUpdate 不写跳转到相同组件(比如 user/1user/2)时,页面不会更新
异步未处理错误加 try/catch,或者重定向到错误页

 二、路由元信息

Vue Router 中的路由元信息(meta是一个非常强大但简单的功能,常用于在路由配置中添加额外的自定义数据,比如:

  • 是否需要登录权限

  • 当前页面的标题

  • 页面缓存控制

  • 菜单显示图标

  • 动态路由权限判断

1、什么是路由元信息?

meta 是路由对象中的一个可选字段,用于存储自定义的附加信息,Vue Router 不会主动使用,但你可以在导航守卫、组件中等地方访问并利用它

语法结构示例

{path: '/admin',component: AdminView,meta: {requiresAuth: true,title: '管理后台',icon: 'admin-icon',cache: true}
}

这段配置的含义就是:

  • 访问 /admin 时,需要登录

  • 页面标题是“管理后台”

  • 菜单显示图标为 admin-icon

  • 页面可以缓存

2、 怎么访问 meta?

你可以通过 route.meta 来访问元信息: 

1. 在全局导航守卫中:
router.beforeEach((to, from, next) => {if (to.meta.requiresAuth && !isLoggedIn()) {next('/login')} else {next()}
})2. 在组件中访问:
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.meta.title) // 页面标题

3、典型应用场景(非常实用)

应用场景用法示例
登录权限控制meta: { requiresAuth: true }
页面标题设置meta: { title: '首页' }
动态菜单渲染meta: { icon: 'home', hidden: false }
缓存控制meta: { cache: true } 配合 keep-alive
用户角色权限meta: { roles: ['admin', 'editor'] }
是否展示标签页meta: { tag: true }(多标签页路由)

4、注意事项

项目说明
meta 是用户自定义的Vue Router 不会解释它,你自己怎么用都行
子路由也可以有 meta如果没有,你可以继承父路由的 meta
需要在组件或守卫中访问 route 对象使用 useRoute() 获取当前路由信息

meta 是 Vue Router 路由配置中的“万能自定义字段”,你可以往里面塞权限标记、页面标题、缓存控制、菜单信息等任意逻辑,再通过路由守卫或组件动态处理。 

三、 <RouterView> 插槽

RouterView 是 Vue Router 提供的内置组件,专门用来渲染“命中的子路由组件”。
而它的插槽(slot)机制,让我们可以更灵活地控制它所渲染的内容。

从 Vue Router 4 开始,<RouterView> 支持默认插槽和作用域插槽。

1、使用插槽做什么?

通过插槽你可以:

用途说明
✨ 页面过渡动画为切换的路由组件加动画
🌀 加载指示器在组件未加载前显示 loading
🎯 动态包装自定义如何渲染子组件,例如加布局、卡片框等

2、 插槽语法

<RouterView v-slot="{ Component, route }"><!-- 自定义展示方式 -->
</RouterView>变量	说明
Component	当前要渲染的子路由组件
route	当前激活的路由对象(等同于 useRoute())

 示例:为路由组件加过渡动画

<RouterView v-slot="{ Component }"><Transition name="fade"><component :is="Component" /></Transition>
</RouterView>
📌 解释:你接管了 RouterView 默认渲染行为自己通过 <component :is="Component" /> 渲染它可插入 <Transition> 包裹来加动画

3、使用场景总结

场景解决问题
组件加载前展示 loading配合 <Suspense>
切换页面时添加过渡动画<Transition>
自定义布局结构包装组件外层加卡片/容器等
统一处理错误提示在外层判断并渲染 fallba

 三、路由懒加载

路由懒加载(Route Lazy Loading) 是 Vue Router 中的一个优化技巧,主要目的是:

将路由组件按需加载,而不是一次性全部加载,从而提升首页加载速度、减少初始包体积、加快页面响应

1、什么是“懒加载”?

懒加载(Lazy Load)就是在用户访问某个路由时才去加载对应的组件代码

不是在一开始加载整个应用时就加载所有路由页面,而是需要时再加载、用完即用

2、为什么需要懒加载?

不懒加载时会发生什么?

  • 项目中所有页面组件在第一次打开应用时全部加载

  • 首屏加载时间变慢(特别是页面很多时)

  • 用户可能只访问其中某几个页面,却加载了所有组件

 3、懒加载的实现方式

传统方式(同步加载)

import Home from '@/views/Home.vue'const routes = [{ path: '/', component: Home }
]缺点:Home.vue 会在页面初始化时就被加载

 推荐方式:使用 import() 动态导入

const Home = () => import('@/views/Home.vue')const routes = [{ path: '/', component: Home }
]

这个语法的核心:

  • import() 返回一个 Promise

  • Vue 会把这个组件单独打包成一个 懒加载 chunk

  • 当你访问 / 时,它才会发起网络请求下载该页面代码

4、懒加载适合什么项目?

项目类型是否建议使用懒加载
小型 SPA,页面少不强制,可选
多页面、功能复杂✅ 强烈建议懒加载
管理系统、CMS、商城✅ 一定要懒加载
首屏要极快响应✅ 可只加载核心页面,其它懒加载

 四、动态路由

1、什么是动态路由?

动态路由是指:你可以在路由路径中定义“参数变量”,从而匹配不同的 URL,渲染相同的组件但显示不同的内容

基础语法

 路由配置:
{path: '/user/:id',component: UserDetail
}
:id 是一个动态路径参数访问 /user/1、/user/2 会匹配同一个路由,但参数不同
在组件中获取动态参数

 在 <script setup> 中:

import { useRoute } from 'vue-router'const route = useRoute()
console.log(route.params.id) // 输出当前的用户 ID
你可以用它去请求对应用户的数据:
const res = await fetch(`/api/user/${route.params.id}`)

动态参数更新时自动响应

问题:

访问 /user/1 后,再跳转 /user/2组件不会重新创建,这时你要用:

import { onBeforeRouteUpdate, useRoute } from 'vue-router'const route = useRoute()onBeforeRouteUpdate((to, from, next) => {// 监听参数变化fetchData(to.params.id)next()
})

 或者使用 <watch> 监听 route 变化。

props 配合动态参数(推荐做法)
路由配置:
{path: '/user/:id',component: UserDetail,props: true
}
✅ 组件中直接用 props 接收参数:<script setup>
const props = defineProps(['id'])
</script>
这样你无需手动解析 useRoute(),更干净、易测试。

2、什么是动态路由添加?

通俗解释:

动态路由添加就是:在运行时动态注册新的路由,而不是一开始就写死在 routes 里。

常见于以下场景:

  • 登录后根据权限动态添加路由

  • 加载某个模块时再注册其页面路由

  • 插件/微前端中按需注册子应用路由

 动态添加路由的基本方法:router.addRoute()

router.addRoute({ path: '/about', component: About })
这样会将 /about 的路由 添加进当前路由系统中。

 🧠 但注意:
如果你当前已经在 /about 页面上了,它会继续显示之前的匹配结果,比如 /:articleName,因为 Vue Router 只在切换路由时重新匹配!

解决办法

// 添加新路由
router.addRoute({ path: '/about', component: About })
// 替换当前路径以强制重新匹配
router.replace(router.currentRoute.value.fullPath)这样 Vue Router 才会重新匹配新添加的 /about 路由,并正确渲染 About 组件。

3、在导航守卫中动态添加路由

动态加载路由的同时判断是否已有该路由,并触发重定向。

router.beforeEach(to => {if (!hasNecessaryRoute(to)) {router.addRoute(generateRoute(to))   // 添加路由return to.fullPath                   // 触发重定向}
})

📌 解释:

  • hasNecessaryRoute():判断当前要访问的路由是否已经注册

  • 如果没有 → 添加 → 返回 to.fullPath 触发跳转(类似 next(to.fullPath)

🔁 必须小心处理递归添加/跳转,以防无限重定向

4、如何删除路由?

✅ 方式一:名字相同会覆盖

router.addRoute({ name: 'about', path: '/about', component: About })
router.addRoute({ name: 'about', path: '/other', component: Other })
// 原来的 'about' 路由会被删除,新的替代

方式二:使用 addRoute() 返回的函数

const remove = router.addRoute({ path: '/settings', component: Settings })
remove() // 取消注册该路由
适合用于组件挂载时注册、卸载时移除。

 方式三:显式调用 router.removeRoute(name)

router.removeRoute('about')
⚠️ 只能删除命名路由

 5、动态添加嵌套路由(children)

// 添加父路由
router.addRoute({ name: 'admin', path: '/admin', component: Admin })
// 向 admin 路由添加子路由
router.addRoute('admin', { path: 'settings', component: AdminSettings })
等价于:
{name: 'admin',path: '/admin',component: Admin,children: [{ path: 'settings', component: AdminSettings }]
}

动态嵌套路由常用于:

  • 模块懒加载时

  • 子模块按需注册

6、查看和判断当前路由表

Vue Router 提供两个方法:

方法功能
router.hasRoute(name)判断某个命名路由是否存在
router.getRoutes()获取所有当前注册的路由(包括

示例

// 添加
if (!router.hasRoute('dashboard')) {router.addRoute({ name: 'dashboard', path: '/dashboard', component: Dashboard })
}// 删除
if (router.hasRoute('dashboard')) {router.removeRoute('dashboard')
}

7、总结

动态路由让你可以在运行时控制哪些页面存在、哪些功能可访问,是构建权限控制、模块懒加载、大型系统菜单的关键机制。配合 addRoute()removeRoute()router.replace() 使用可以灵活操作整个路由系统。

http://www.xdnf.cn/news/279505.html

相关文章:

  • idea创建springboot项目无法创建jdk8原因及多种解决方案
  • 递归下降算法
  • 结构型模式:外观模式
  • Python 数据智能实战 (12):效果评估 - 超越传统指标
  • 平台介绍-开放API接口-IO说明
  • 阿里云服务器全栈技术指导手册(2025版)
  • 基于 PyQt 的YOLO目标检测可视化界面+ nuitka 打包
  • Spring AI 实战:第六章、Spring AI源码浅析之一山可容二虎
  • 实验四 增强型可靠文件传输系统
  • 电容电阻作用
  • PostgreSQL 表的年龄(age)详解
  • 从 Java 开发到 AI 工程师:全面学习指南
  • C++多继承陷阱全解:虚析构函数与虚表布局的工程实践
  • 方案精读:业财融合转型路径和华为实践【附全文阅读】
  • 质检报告警示:亚马逊等平台3成节能插座不达标
  • [特殊字符]Spring Boot 后台使用 EasyExcel 实现数据报表导出(含模板、样式、美化)
  • 【iOS】 方法交换
  • Linux文件权限管理:chmod修改权限 与 chown修改所有者
  • Android第三次面试总结之网络篇补充
  • 力扣-链表-2 两数相加
  • 情绪ABC——AI与思维模型【93】
  • # 基于SIFT的图像相似性检测与拼接:Python实现与解析
  • 精品,CentOS7.9 Yum安装Nginx,并配置JSON日志格式
  • Matlab/Simulink - BLDC直流无刷电机仿真基础教程(七) - 波形解析专题P2
  • Java 中使用 Callable 创建线程的方法
  • FastApi快速实践
  • React class 的组件库与函数组件适配集成
  • C++函数总结
  • 【Java学习笔记】方法重载
  • 以太坊智能合约开发框架:Hardhat v2 核心功能从入门到基础教程