vue-router 完成剖析

vue-router 是 Vue.js 官方的路由库,本着进修的目标,我对 vue-router 的源码举行了浏览和剖析,分享出来给其他感兴趣的同砚做个参考吧。

参考

开端

我们离别从差别的视角来看 vue-router。

  • 从开发者角度来看,是如许的:

var router = new VueRouter({
  routes: [
   {path: '/foo', component: {template: '<div>FOO</div>'}},
   {path: '/bar', component: {template: '<div>BAR</div>'}}
  ]
})

var vm = new Vue({
  el: '#app',
  router: router
})

我们建立一个 router,传入的 routes 中的每一项即为一条路由(route)设置,示意在婚配给定的地点时,应当运用什么组件衬着视图。

router 传入 new Vue() 用于建立根组件,如许根组件中对应的视图地区,能够基于 router 中的设置,依据页面地点显现差别的内容。固然,这还需要在组件模板中运用 <router-view> 来定义地区。

  • 从视图角度来看,是如许的:

<div id="app">
  ...
  <router-view></router-view>
  ...
</div>

页面地点变动后,<router-view> 对应的地区会更新为地点婚配的组件。比方,途径是 /foo 则对应地区显现 FOO,途径是 /bar 则显现 BAR,途径没有婚配的组件时,则不显现内容。

  • 从数据角度来看,是如许的:

vm
+ _router | $router
  - history
  - matcher
+ _route | $route
  - matched

vm.$router 援用当前组件对应的 router 对象,该对象在初始化时(在 vm 建立历程当中实行初始化),会启动对页面地点变动的监听,从而在变动时更新 vm 的数据($route),进而触发视图的更新。

深切

怎样完成对地点变动的监听?

关于缺省的 HashHistory 形式(也就是基于页面地点的 hash 部分来完成路由功用,如 http://example.com/path#/foohttp://example.com/path#/bar),是经由历程监听 hashChange 事宜来完成:

window.addEventListener('hashchange', () => {
  // this.transitionTo(...)
})

源码

这个行动是什么时刻实行的呢?

是在 router.init()源码)中挪用的,而 router.init() 则是在根组件建立时(源码)挪用的。

而 Vue 组件在建立时,又怎样会去挪用 router.init() 呢?

这是因为 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 上。

只是举行了赋值,为何 vm 就能够感知到路由的转变了呢?

答案在 vue-router 注入 Vue 的 beforeCreate 钩子函数中(源码):

Vue.util.defineReactive(this, '_route', this._router.history.current)

采纳与 Vue 自身数据雷同的“数据挟制”体式格局,如许对 vm._route 的赋值会被 Vue 阻拦到,而且触发 Vue 组件的更新衬着流程。

地点变动假如同步视图更新?

接上一步,vm._route 已接收到路由的变动,从而触发视图更新。而当视图更新进一步挪用到 <router-view>render() 时,即进入了 <router-view> 的处置惩罚(源码)。

<router-view>render() 采纳函数挪用(h())形式,而非经由历程模板天生。这也是 Vue2 支撑的定义组件衬着逻辑的体式格局,相似 React 的 render()。采纳这类形式的优点是能够完整运用 JavaScript 的才能来编写逻辑,没必要受制于 Vue 的类 HTML 模板语法。

这里的重要处置惩罚逻辑是从根组件中掏出当前的路由对象(parent.$route),然后获得该路由下对应的组件,然后交由该组件举行衬着:

return h(component, data, children)

这个中还触及 <router-view> 嵌套的处置惩罚,不过重要逻辑就是如许了。

小结

实在 vue-router 从 <router-view> 的完成来看,就是一个具有特定功用的 Vue 组件罢了,不过要合营根组件的 router 发挥作用。但团体照样很“相应式”的,也是蛮“Vue作风”的。

vue-router 以插件体式格局“侵入”Vue,从而支撑一个分外的 router 属性,以供应监听并转变组件路由数据的才能。如许每次路由发作转变后,能够同步到数据,进而“相应式”地触发组件的更新。

<router-view> 作为根组件下的子组件,从根组件那边能够获取到当前的路由对象,进而依据路由对象的组件设置,掏出组件并用其替代当前位置的内容。如许,也就完成全部路由变动到视图变动的历程。

路由变动到视图变动的历程整顿为:

hashchange
-->
match route
-->
set vm._route
-->
<router-view> render()
-->
render matched component

完成历程当中的手艺点包含:

  • Vue 插件机制

  • 相应式数据机制

  • Vue 衬着机制

  • 地点变动监听

末了

我写了一个运用 Vue.js、vue-router 以及其他 Vue 相干东西(Vuex、vue-loader)的示例,感兴趣能够看下:luobotang/vue-demo – github

    原文作者:luobotang
    原文地址: https://segmentfault.com/a/1190000008831927
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞