Vue-Router3源码拾遗【1】概述

若要深挖 Vue-Router 的源码,代码真的是又臭又长。本系列依旧提取源码中的核心原理并且尽量用文本概括繁杂的逻辑流程。

Vue-Router 实际上只适用于单页应用(其实这个结论是可以推理出来的)。而像 Nuxt 之类的看似是用到了 Vue-Router 且像是多页的,实际上是它们是用到了多个 Vue-Router。记住单页与多页的区分,这个区分贯穿了本文的脉络。

说到“前端路由”,若不懂以下浏览器 BOM api,就没法往下说了。详细介绍 api 的工作还是留给其他人好了,以后除非要debug这些库,是接触不到这些经封装的底层的 api 的。这里主要是完整地列举一下原理用到的部分,好留一个印象。

前置知识

在这一小节中,就算没掌握 api 的用法也没关系,关注的核心还是 history 系列 api ,而一起列举其他的 api 起到对比的作用。

下面比较完整地列举了一下 Vue-Router 原理可能涉及到的3大类 BOM api:

  • location: 全是多页的模式
    • ------------ 获取url参数 或 query参数: --------------
    • url参数获取先略
    • query参数:从location.search获取才是正解
    • ------------ 利用location,重载页面或跳转 --------------
    • 【1】重新加载页面:window.location.reload(/**/)
      • 如果不传任何参数 【相当于F5】
      • 如果传入参数true时 【这个参数因不在规范里面已经被废弃】【相当于ctrl + F5】
        • ( 注意:给路径加上时间戳也可以实现ctrl + F5的效果。 )
    • 【2】跳转:window.location.assign(url)或者直接修改window.location.href
    • 【3】“栈帧替换”跳转:window.location.replace(url)
      • 用来实现过渡页面时,非常好用
      • 但是有些webview却是反而不支持这个老api的,那就改用history.replaceState+window.location.reload()
        • 比如在开发的钉钉上的微应用的时候就不支持
  • history
    • 早期history:history.go()、history.forward()、history.back()
      • (等价地囊括)对应用户的点击操作
      • 即可用于多页,也可用于单页
    • 【重要】HTML5 history
      • pushState 和 replaceState,可以设置history.state并改变 url 地址,但不会刷新页面
      • popstate 事件,不会去监听 pushState/replaceState
        • 无论在单页还是多页,主要作用就是监听前进后退
        • 点击浏览器前进后退 或者 调用早期history的 back() go() forward()方法的时候才会触发
  • hash:hash变化时不需要刷新页面
    • 监听hashchange事件
      • window.onhashchange
      • window.addEventListener(hashchange, /**/)

再来(用大白话)总结一下:

  • location 主要有2种作用:获取各种url参数+提供api主要用来控制页面的刷新和跳转
  • location 的全部 api 就是把网页视为传统的“多页”的模式
  • histroy api可以分为“早期 history”和“HTML5 history”

这里我们看到“早期 history” vs “HTML5 history”;“单页” vs “多页”。下面我们再从另外一个分类的角度来重新看它们间的关系:

前端路由概述和对比: #重要

vue-router只适用于单页应用

早期history:在单页应用的时代不是主力,但是仍有作用

  • 多页:后端路由返回不同html
    • 可利用location实现跳转
    • 早期history
  • 单页:【通过vue-router来了解】
    • 本质:监听url变化不刷新页面,而只更新部分内容
    • 类型:
      • hash:在改变 hash 的情况下,访问的还是同一个页面,(不会去请求新页面,)只是局部更新html。
        • 通过改变路由的hash值并且监听hash变化
      • HTML5 history + 早期history
      • 虚拟路由

以上,就涵盖了所有互联网上的浏览器网页的“路由”的实现原理。

上面仅仅是基础知识,有了基础知识之后,我们再来看看相关的问题的解答:

单页的HTML5 history和hash对比 #已齐全 #面试常问

  • 原理和本质:前者不同路由是不同地址;后者不同路由其实是同一个地址
    • ( 前者基于url的pathname段,后者基于hash段 来标识。 )
    • ( 对于单页应用:api如上小节所说:HTML5 history + 早期history vs hash )
  • 适用范围:前者可用于多页和单页;后者只能单页
  • 兼容性:react更推荐前者,而后者能兼容更多浏览器
  • 刷新单页缺陷:刷新单页HTML5 history的页面需要服务器端配合:
    • 当用户刷新页面之类的操作时,(真正地去访问对应url,)浏览器还是会给服务器发送请求页面。
    • 为了避免出现这种情况,所以这个实现需要服务器的支持:所有页面重定向到首页路由

明白了上述概念,再来看 Vue-Router的核心原理就不难了:

vue-router的实现原理概述

  • api:屏蔽底层的browser history和hash history
    • api降级:如果不支持HTML5 history(比如IE9环境下),就会降级成hash
  • 整体架构: 【react-router可能也不过如此???】
    • 抽象出 route 当前路由对象,它和浏览器原生的 url 互相同步
      • 提供路径切换的回调,承载改变url之类的操作
      • 核心函数调用路径切换回调和其前后的路由守卫
    • 实现matcher
    • 提供视图渲染的组件 和 封装跳转的组件
  • 设计模式
    • 迭代器模式
  • ( 记录访问过的路由。通过计算,让vue组件调用activated或者deactivated钩子 )
文章目录
  1. 前置知识
  2. 前端路由概述和对比: #重要
  3. 单页的HTML5 history和hash对比 #已齐全 #面试常问
  4. vue-router的实现原理概述