VueRouter原理分析

关于VueRouter

vue-router 是 Vue.js 官方的路由库,负责在单页应用中将组件(components)映射到路由(routes),然后告诉 vue-router 在哪里渲染它们。VueRouter由三大组成部分:vue-router、router-link、router-view。

  • vue-router:路由器类,根据路由请求在路由视图中动态渲染选中的组件
  • router-link:路由链接组件,声明用以提交路由请求的用户接口
  • router-view:路由视图组件,负责动态渲染路由选中的组件

路由过程:由router-link发起路由请求到vue-router,然后vue-router根据路由表进行路由决策,并告知router-view进行视图更新,最后由router-view完成动态视图更新。

VueRouter原理

单页应用(SPA)的核心之一就是更新视图而不重新请求页面,实现这个功能主要是两种方式:Hash、History。

  • Hash模式: 通过改变hash值实现页面更新
  • HTML5 History模式:利用HTML5 History Api来模拟完整的URL实现页面更新

在vue-router中,它提供mode参数来决定采用哪一种方式,选择流程:默认Hash–>如果浏览器支持HTML5 History新特性改用HTML5 History–>如果不在浏览器环境则使用abstract,之所以是这样的顺序是因为“#”太丑了。

不管理是哪种模式,它的调用流程都是一样的:

  • push 、replace 、listen
  • transitionTo
  • updateRoute
  • app._route = route
  • vm.render()

HTML5 History模式有个缺陷:不能刷新页面。因为它是完整URL会向后台发请求,会返回404错误,所以需要后台增加一个覆盖所有情况的候选路由,返回index页面。

VueRouter实现

如何实现对地址变更的监听?

关键词:插件机制

vue-router 将自身作为一个插件安装到了 Vue,通过 Vue.mixin() 注册了一个 beforeCreate() 钩子函数,从而在之后所有的 Vue 组件创建时都会调用该钩子函数,给了检查是否有 router 参数,从而进行初始化的机会。进而通过层层调用执行了监听 hashchange 事件的动作。

  • new Vue()
  • 执行 vue-router 注入的 beforeCreate 钩子函数
  • 执行 router.init(vm)
  • 执行 history.setupListeners(),注册事件监听

地址变更如何通知到 vm?

关键词:数据响应机制

这个过程比较简单,在监听 hashchange 时,执行 history.transitionTo(…),在这个过程中,会进行地址匹配,得到一个对应当前地址的 route,然后将其设置到对应的 vm._route 上。
vue-router采用与 Vue 本身数据相同的“数据劫持”方式,这样对 vm._route 的赋值会被 Vue 拦截到,并且触发 Vue 组件的更新渲染流程。

地址变更如果同步视图更新?

关键词:渲染机制

接上一步,vm._route 已经接收到路由的变更,从而触发视图更新。而当视图更新进一步调用到 router-view 的 render() 时,即进入了 router-view 的处理。

router-view 的 render() 采用函数调用模式,而非通过模板生成。这也是 Vue2 支持的定义组件渲染逻辑的方式,类似 React 的 render()。采用这种模式的好处是可以完全利用 JavaScript 的能力来编写逻辑,不必受制于 Vue 的类 HTML 模板语法。

这里的主要处理逻辑是从根组件中取出当前的路由对象(parent.$route),然后取得该路由下对应的组件,然后交由该组件进行渲染。