[路飞] vue-router 插件原理初探

147 阅读2分钟

Vue插件是什么?

是一段程序,这段程序利用Vue的现有能力(API),去增加未有的Vue能力(逻辑)。

为什么规定插件对象如VueRouter一定要传入Vue.use?

使用Vue.use可以统一插件的入口函数,将插件的入口函数统一为install。当所有插件以install为入口,则更容易找到插件入口降低心智负担。而如果没有Vue.use,以VueRouter为例,入口函数不一定是VueRouter.install,而可以随意取任何函数名如VueRouter.load、VueRouter.register。

VueRouter插件利用了哪些Vue现有能力(API),又拓展了哪些Vue的未有能力?

  • VueRouter为Vue新增了一个原型属性,该属性维护了current url和url路由表(url映射component)等信息,属性名为$router。作为Vue的原型属性,该属性在所有的Vue实例上都能被访问到。(利用Vue.mixin API)
  • VueRouter插件为Vue实现了两个全局组件(利用Vue.component API):
    • 第一个组件:在用户点击时改变current url,名为router-link
    • 第二个组件:在url改变时自动重新匹配组件,把新组件渲染到界面上,名为router-view(利用Vue.util.defineReactive API)

VueRouter如何为Vue新增原型属性?

  • 要点一:把需要新增的原型属性,在Vue实例化时,传入:
new Vue({
  router, // 需要新增的原型属性router
  render: h => h(App)
}).$mount('#app')
  • 要点二:提前,在Vue实例化前,通过定义beforeCreate,把"新增原型属性"的逻辑添加到Vue实例化的逻辑中:
Vue.mixin({
    // beforeCreate定义的代码在Vue实例化时执行
    beforeCreate(){
        if(this.$options.router){  //通过$options拿到传入的router
            Vue.prototype.$router = this.$options.router
        }
 
    }
})

VueRouter的router-view是如何做到在url改变时重新匹配新组件进行渲染显示?

  • 要点一:将原型属性router中的current url作为hashchange事件的下游观察者:
window.addEventListener('hashchange',()=>{
    // this = router
    this.current = window.location.hash.slice(1)//一旦路由改变,current url就改变
})
  • 要点二:current url作为观察者后,可以接着成为发布者,把观察到的信息接着发布给它的下游:
// 使用Vue.util.defineReactive将current url变为发布者。响应式属性 = 发布者
// this = router
Vue.util.defineReactive(this,'current',window.location.hash.slice(1))
  • 要点三:因为在Vue框架内,任何组件的render函数天生是响应式属性的下游观察者,在这里,router-view组件的render函数是current url这个发布者的观察者。所以,只需要在render函数中实现"匹配组件进行渲染"的逻辑,就大功告成。经过层层的两级观察,当hashchange事件触发,就会重新执行router-view的render函数:
Vue.component('router-view',{
    render(h){
        const { options,current } = this.$router
        const route = options.routes.find(route=>route.path === current)

        return h(route.component)
    }
});