tomoya06 / web-developer-guidance

Actually it's just a notebook for keeping down some working experience.
4 stars 0 forks source link

Vue - Router #36

Open tomoya06 opened 3 years ago

tomoya06 commented 3 years ago

Vue Router 原理解析

简介

Vue Router是使用Vue开发SPA时常用的前端路由管理系统。与传统的页面跳转相比,SPA的区别在于:

  1. SPA是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。
  2. 传统的页面应用,是用一些超链接来实现页面切换和跳转的。

在vue-router开发的SPA中,页面的切换的切换实际是路径之间的切换,引起组件的切换,从而实现了SPA对页面跳转的要求:不刷新或重新获取页面就能完成页面跳转。

前端路由

在SPA中,前端路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)。

要实现前端路由,需要解决两个核心问题:

  1. 如何改变 URL 却不引起页面刷新?
  2. 如何检测 URL 变化了?

实现原理

Vue router支持两种路由模式,分别是hash模式(默认)和history模式。两种模式对核心问题2的解决原理分别如下。

hash mode

hash 模式使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。

hash模式通过 hashchange 事件 来监听 URL 的变化,改变 URL 的方式只有这几种:

  1. 通过浏览器前进后退改变 URL
  2. 通过标签改变 URL
  3. 通过修改window.location改变URL

history mode

History API提供了popState事件,可以用来监听活动历史记录条目更改。另外提供了 pushStatereplaceState 两个方法,这两个方法改变 URL 的 path 部分不会引起页面刷新。

popState的触发情况有些特殊

  1. 通过浏览器前进后退改变 URL 时会触发 popstate 事件
  2. 调用history的back,go,forward方法会触发该事件
  3. 调用pushState/replaceState方法或点击<a>标签改变 URL 不会触发 popstate 事件,需要拦截 pushState/replaceState的调用和<a>标签的点击事件来检测 URL 变化

另外,使用history模式时,后端需要特别配置。参考router博客提供的方案

API

编程式的导航

除了使用<router-link>创建 a 标签来定义导航链接,我们还可以借助 router的实例方法,通过编写代码来实现。

在 Vue 实例内部,你可以通过 $router 访问路由实例。可以调用this.$router.push() / .replace() / .go()方法来导航。

路由对象

一个路由对象 (route object) 表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息,还有 URL 匹配到的路由记录 (route records)。

路由对象是不可变 (immutable) 的,每次成功的导航后都会产生一个新的对象。在多个地方可以出现,参考API文档

动态路由匹配

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:

const router = new VueRouter({
  routes: [
    // 动态路径参数 以冒号开头
    { path: '/user/:id', component: User }
  ]
})

现在像 /user/foo/user/bar都将映射到相同的路由。

注意,当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。

复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route对象,或者使用 beforeRouteUpdate导航守卫。

404路由捕获

如果想匹配任意路径,我们可以使用通配符 (*),含有通配符的路由应该放在最后,这样就可以捕获404错误。

有时候同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。