Vue-Router源碼分析之install方法

系列文章:前端

Vue-Router 源碼學習之咱們從API中看些門道vue

Vue-Router源碼分析之index.jsnode

Vue-Router源碼分析之install方法面試

Vue是怎麼註冊插件的呢?

使用過Vue的coder都知道,若是想註冊一個vue的插件,在vue對象上可以使用的話(並非綁在Vue.prototype上的那種暴力方式),必須使用Vue.use(你的插件)的方式來註冊插件,vue-router

用use註冊插件須要注意什麼呢?

Vue.use方法會尋找插件上的install方法,而且執行,若是插件沒有install方法的話,就會報錯,沒法使用use來註冊插件。 哦喲,是真的傲嬌的一匹,因此想要使用VueRouter插件的話,就必須擁有一個install方法,app

這麼一看Vue的插件都須要install方法

因此咱們來看看VueRouter的install方法都作了什麼?函數

代碼實在是很多,我是真的沒辦法一口氣複製過來,截個圖先給你們作一個展現吧

install 作了那幾件事?

簡單看來: Vue.mixin:侵入式的對每一個Vue component進行了擴展源碼分析

用ES5的defineProperty的方式設置 $router$route屬性。

建立了routerView 與RouterLink兩個組件

對路由鉤子進行一個統一設置(這塊沒看Vue.config.optionMergeStrategies)的源碼,目前還不是很熟,固然這不重要了。先往下看

Vue-Router如何使用Vue的內容

你們都知道,Vue.mixin、Vue.component都是Vue類的方法,Vue-Router想要使用的話就必須引入Vue,這是毋庸置疑的,可是若是把Vue打包進入Vue-router的源碼內,這必然致使Vue-router的包變得很大,post

關鍵問題!!! 目前沒有發現用Vue開發時哪一個使用Vue-router開發不提早引入Vue的。學習

// 聲明一個私有的_Vue用來接收外部的Vue類。
export let _Vue
//install方法接收一個參數,也就是Vue類
export function install (Vue) {
  // 若是已經被註冊了,而且
  if (install.installed && _Vue === Vue) return
  install.installed = true
  //把Vue類賦值給私有_Vue
  _Vue = Vue
複製代碼

這種方式只須要在install的時候使用全局的Vue類,並不須要將Vue打包進入Vue-router的源碼內。

減小沒必要要的依賴,從我大Vue-router作起。

const isDef = v => v !== undefined
//這是install方法中一個判斷值是否爲undefined的方法,在接下來會有不少次調用到它,請不要遺漏
複製代碼
// 註冊實例的方法
const registerInstance = (vm, callVal) => {
    //vm是什麼?就是vue componet實例
    let i = vm.$options._parentVnode
    // 這是一個相似鏈式調用的方式
    // 目的是確保能肯定到this.$options._parentVnode.data.registerRouteInstance是否是存在?
    // 若是找到了那麼就天然而然的把i賦值爲這個方法,而後執行它
    if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
      i(vm, callVal)
    }
}
複製代碼

說到這裏可能會很亂,咱們先留下來這個內容,一會去看看哪裏會調用它。

mixin 侵入了哪裏?

Vue.mixin({
    beforeCreate () {
      // 只有根節點的$options的屬性中有router
      if (isDef(this.$options.router)) {
        this._routerRoot = this
        this._router = this.$options.router
        this._router.init(this)
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this, this)
    },
    destroyed () {
      registerInstance(this)
    }
  })
複製代碼

看到這裏咱們應該瞭解,Vue-Router在install的時候侵入了每一個vue componet的beforeCreate以及destroyed生命週期鉤子中,在建立以前以及摧毀的時候作一些事情。 作了什麼呢? 咱們好像看到了registerInstance方法。

// 接受了vue componet本身
registerInstance(this, this)
複製代碼

這個時候從新看一下這個方法,意思就是尋找這個方法去調用一下,this.$options._parentVnode.data.registerRouteInstance(這個方法誰有呢?) 這個我也不知道,我就寫在一個子組件內的方法,去查看一下它的父組件們族譜中誰有這個方法。

(function(t){
     while(t){
        if(typeof t.$options._parentVnode.data.registerRouteInstance === 'function'){
            return t
        }else{
            t = t.$parent
        }
    }
        return 'not find'
})(t)
複製代碼

各位看官這是一個很拙劣的方法(勿學)之後會優化這個方法的。 而後發現這個this是誰呢?就是在你使用vue-router時,那個咱們對每一個組件設置path的那個組件。能夠看下面

new vueRouter({
    xxx
    routes : [{
        path : 'xxx',
        component : '某某組件'
    }]
})
複製代碼

每一個有這個方法的應該都是這裏面設置過的組件,全部我就有一個猜想,是否是路由的改變會致使該路徑跳轉先後的組件進行生成與摧毀(展現與隱藏)在這些組件建立以前會調用registerInstance方法(這個方法我還沒看內部實現)。之後會去驗證這個猜想的準確程度。

終於知道這個registerInstance何時執行了

router這個屬性誰有啊????

//this.$options.router是綁定在app根節點的組件上。全部只有根組件有這個router屬性
 //因此全部的vue component的_routerRoot、_router、都是同樣的。
 
 // this.$options.router存在嗎?==》 是否是已經綁定萬_routerRoot的根節點
 if (isDef(this.$options.router)) {
       // 根節點的_routerRoot就是根節點的vue component
        this._routerRoot = this
        // vue router實例
        this._router = this.$options.router
        // 執行init
        this._router.init(this)
        Vue.util.defineReactive(this, '_route', this._router.history.current)
      } else {
        // 若是沒有這個屬性 ==》 兩種狀況 還沒綁定這個屬性的根節點、不是根節點
        // 未綁定屬性的根節點組件,(根節點組件怎麼會有爸爸呢)它不存在$parent屬性、因此仍是指向了本身
        // 不是根節點組件,那就找它爸爸的_routerRoot屬性,用它爸爸的
        // vue的子組件beforeCreate確定晚於父組件beforeCreate因此
        // 全部的組件就像一棵組件樹以同樣你們,從根向全部樹枝樹杈去傳遞這個屬性
        // 你們都是用一個屬性因此每一個組件的_routerRoot都是根節點組件
        this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
      }
      registerInstance(this, this)
複製代碼

因此你們能夠嘗試的在vue項目中打印出組件自己,查看_routerRoot屬性時,每一個組件的uid都是同樣的,$el也是根節點標籤的id 。這不實錘了!!

總結一下

咱們能夠看出來在vueRouter在註冊方面有哪些重要的事?

  • 1:並無將Vue打包進入Vue-router插件,而是使用外部Vue引入的方式。

  • 2: mixin侵入式的給每一個Vue組件的beforeCreate與destroyed生命週期對組件指定路由組件進行了建立與摧毀。

  • 3:全部Vue組件的_router都是同一個Vue-router實例,總之你們都是用一個的。

install方法就介紹到這裏,下一節會開始講述Vue-router的主構造函數。前端er,下一期不見不散

我是一個應屆生,最近和朋友們維護了一個公衆號,內容是咱們在從應屆生過渡到開發這一路所踩過的坑,已經咱們一步步學習的記錄,若是感興趣的朋友能夠關注一下,一同加油~

我的公衆號:IT面試填坑小分隊
相關文章
相關標籤/搜索