vue知识点之vue-router

118 阅读5分钟

1. vue-router的原理是什么?

Vue Router 的核心是通过 路由模式监听 URL 变化动态匹配组件响应式更新视图,实现单页面应用的无刷新导航。选择 Hash 或 History 模式需根据项目需求权衡美观性、兼容性和服务器支持。对于复杂场景,可结合导航守卫、懒加载等特性优化用户体验

路由模式的核心实现

Vue Router 支持三种路由模式,其底层机制如下:

  1. Hash 模式(默认模式)
  • 原理:利用 URL 中的 # 符号(哈希值)作为路由标识。哈希值的变化不会触发浏览器向服务器发送请求。
  • 实现方式
    • 通过 window.addEventListener('hashchange', callback) 监听哈希变化。
    • 哈希值变化时,解析路径并匹配对应组件,通过 <router-view> 动态渲染。
  • 优点:兼容性好(支持所有浏览器),无需服务器配置。
  • 缺点:URL 中带有 #,不够美观。
  1. History 模式
  • 原理:基于 HTML5 的 History APIpushStatereplaceState),直接操作浏览器历史记录栈。
  • 实现方式
    • 通过 history.pushState()history.replaceState() 修改 URL。
    • 通过 window.addEventListener('popstate', callback) 监听浏览器前进/后退操作。
  • 优点:URL 无 #,更符合传统 URL 结构。
  • 缺点:需服务器配置(所有路径重定向到 index.html),否则直接访问子路径会返回 404。
  1. Memory 模式
  • 原理:通过数组模拟浏览器历史记录栈,不依赖浏览器 API,适用于非浏览器环境(如 Node.js 或移动端)

Vue Router 的核心工作流程

  1. 初始化路由表
    定义路由配置(routes 数组),将路径与组件映射。例如:
javascript


const routes = [
  { path: '/user/:id', component: User }, // 动态路由
  { path: '/parent', component: Parent, children: [...] } // 嵌套路由
];
  1. 监听 URL 变化
    • Hash 模式监听 hashchange 事件,History 模式监听 popstate 事件。
  1. 动态匹配路由
    • 根据当前 URL 解析路径参数(如 /user/123 中的 id=123),匹配路由表中对应的组件。
  1. 组件渲染
    • 通过 <router-view> 组件作为占位符,动态渲染匹配到的组件。
  1. 状态更新
    • 使用响应式变量(如 current)跟踪当前路由状态,触发视图更新。

关键特性与进阶实现

1. 动态路由与嵌套路由

  • 动态路由:通过冒号 : 定义路径参数(如 /user/:id),在组件中通过 $route.params 获取参数。
  • 嵌套路由:通过 children 配置子路由,父组件中嵌套 <router-view> 渲染子组件。

2. 导航守卫

  • 作用:在路由跳转前后执行逻辑(如权限验证、数据预加载)。
  • 类型
    • 全局守卫(router.beforeEach)。
    • 路由独享守卫(beforeEnter)。
    • 组件内守卫(beforeRouteEnterbeforeRouteLeave)。

3. 懒加载

  • 实现:通过动态导入语法(() => import('./Component.vue'))按需加载组件,提升首屏性能

Hash 模式和History 模式对比

对比维度Hash 模式History 模式
URL 美观性带有 ##,更接近传统 URL
兼容性支持所有浏览器需浏览器支持 History API
服务器配置无需特殊配置需配置重定向(如 Nginx 的 try_files
适用场景简单项目、兼容性要求高需 SEO 优化、URL 美观的正式项目

2. 路由守卫的执行顺序是什么?

2.1. 完整执行顺序(从路由 A 跳转到路由 B)

  1. 组件内离开守卫: beforeRouteLeave
    • 触发时机:导航离开当前组件时(如从 A 组件跳转至 B 组件)。
    • 作用:处理离开前的操作(如保存未提交数据)。
    • 注意:可访问当前组件实例 this
  1. 全局前置守卫: beforeEach
    • 触发时机:所有路由跳转的入口拦截。
    • 作用:全局权限验证(如登录状态检查)。
  1. 路由独享守卫: beforeEnter
    • 触发时机:仅针对目标路由(如 B 路由)的拦截。
    • 作用:特定路由的权限控制(如管理员访问限制)。
  1. 组件内复用守卫: beforeRouteUpdate
    • 触发时机仅当组件复用时触发(如动态路由参数变化,如 /user/1/user/2)。
    • 作用:更新组件内数据(如重新获取用户详情)。
  1. 组件内进入守卫: beforeRouteEnter
    • 触发时机:目标组件(B 组件)渲染前。
    • 作用:预加载数据(如异步请求),但无法访问 ****this(需通过 next(vm => {}) 回调获取实例)。
  1. 全局解析守卫: beforeResolve
    • 触发时机:所有前置守卫完成后,导航确认前。
    • 作用:最终安全检查或数据准备(如确保所有异步操作完成)。
  1. 全局后置钩子: afterEach
    • 触发时机:导航完成后。
    • 作用:执行与导航无关的后置操作(如埋点统计、页面标题更新)。

2.2. 二、特殊场景说明

2.2.1. 1. 组件复用时(动态路由参数变化)

  • 执行顺序beforeRouteLeavebeforeEachbeforeRouteUpdatebeforeResolveafterEach
  • 示例:从 /user/1 跳转到 /user/2,复用 User 组件,触发 beforeRouteUpdate

2.2.2. 2. 嵌套路由跳转

  • 执行顺序:父组件的 beforeRouteLeave → 子组件的 beforeRouteLeave → 全局 beforeEach → 子路由的 beforeEnter → 子组件的 beforeRouteEnter

2.2.3. 3. 异步组件加载

  • 触发时机:在 beforeEnterbeforeRouteEnter 之间解析异步组件。
  • 示例:使用 () => import('./User.vue') 动态导入组件时,需等待组件加载完成。

2.3. 三、核心注意事项

  1. next() ****的调用
    • 必须显式调用 next(),否则导航会挂起。
    • 控制跳转:通过 next(false) 中断导航,或 next('/login') 重定向。
  1. beforeRouteEnter ****的特殊性
    • 无法访问 ****this:因组件实例尚未创建,需通过 next(vm => {}) 回调操作实例。
    • 唯一支持回调的守卫:其他守卫可直接访问 this
  1. 错误处理
    • 全局错误捕获:通过 router.onError() 捕获 next(error) 抛出的异常。