Vue源碼分析-Vue.use和vue-router

Vue.use是Vue註冊plugin的一種方法,那麼這個過程當中發生了什麼?經過源碼來看一下,vue註冊plugin的過程。vue

這裏咱們以vue-router爲例,順便看一下vue-router的實現原理。node

Vue.use源碼分析

關於如何尋找源碼,經過查找響應npm包的package.json文件中的main屬性,這就是咱們引入npm包的入口文件的路徑。vue-router

function initUse (Vue) {
  Vue.use = function (plugin) {
    var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    var args = toArray(arguments, 1);
    args.unshift(this);
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args);
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args);
    }
    installedPlugins.push(plugin);
    return this
  };
}
複製代碼

查看這部分源碼,咱們能夠發現vue首先判斷這個插件是否被註冊過,不容許重複註冊。 而且接收的plugin參數的限制是Function | Object兩種類型。 對於這兩種類型有不一樣的處理。npm

若是咱們傳入的plugin(Vue.use的第一個參數)的install是一個方法。也就是說若是咱們傳入一個對象,對象中包含install方法,那麼咱們就調用這個plugin的install方法並將整理好的數組當成參數傳入install方法中。 => plugin.install.apply(plugin, args) 若是咱們傳入的plugin就是一個函數,那麼咱們就直接調用這個函數並將整理好的數組當成參數傳入。 => plugin.apply(null, args) 以後給這個插件添加至已經添加過的插件數組中,標示已經註冊過 => installedPlugins.push(plugin) 最後返回Vue對象。json

看看vue-router的註冊過程

首先咱們按照上面說的方法找到vue-router的源碼數組

import View from './components/view'
import Link from './components/link'

export let _Vue

// 這裏就是在Vue.use中會別執行的install方法
export function install (Vue) {
 if (install.installed && _Vue === Vue) return
 install.installed = true

 _Vue = Vue

 const isDef = v => v !== undefined

 const registerInstance = (vm, callVal) => {
   let i = vm.$options._parentVnode
   if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
     i(vm, callVal)
   }
 }
 // 對Vue實例混入beforeCreate鉤子操做(後續能夠繼續看一下mixin的源碼)
 Vue.mixin({
   beforeCreate () {
     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.prototype定義$router$route 屬性(方便全部組件能夠獲取這兩個屬性)
 Object.defineProperty(Vue.prototype, '$router', {
   get () { return this._routerRoot._router }
 })

 Object.defineProperty(Vue.prototype, '$route', {
   get () { return this._routerRoot._route }
 })
 // Vue上註冊router-link和router-view兩個組件
 Vue.component('RouterView', View)
 Vue.component('RouterLink', Link)

 const strats = Vue.config.optionMergeStrategies
 // use the same hook merging strategy for route hooks
 strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}

複製代碼

Install解析 (對應目錄結構的install.js)bash

該方法內主要作了如下三件事:app

  1. 對Vue實例混入beforeCreate鉤子操做(在Vue的生命週期階段會被調用)
  2. 經過Vue.prototype定義router、router、route 屬性(方便全部組件能夠獲取這兩個屬性)
  3. Vue上註冊router-link和router-view兩個組件
相關文章
相關標籤/搜索