天天看點

淺談Vue.use

先舉個?

我們先來看一個簡單的事例

首先我使用官方腳手架建立一個項目​​

​vue init webpack vue-demo​

​​ 然後我建立兩個檔案​

​index.js plugins.js​

​.

我将這兩個檔案放置在​

​src/classes/vue-use​

​目錄下

接下來對這兩個檔案進行編寫

// 檔案:  src/classes/vue-use/plugins.js

const Plugin1 = {
    install(a, b, c) {
        console.log('Plugin1 第一個參數:', a);
        console.log('Plugin1 第二個參數:', b);
        console.log('Plugin1 第三個參數:', c);
    },
};

function Plugin2(a, b, c) {
    console.log('Plugin2 第一個參數:', a);
    console.log('Plugin2 第二個參數:', b);
    console.log('Plugin2 第三個參數:', c);
}

export { Plugin1, Plugin2 };      
// 檔案: src/classes/vue-use/index.js

import Vue from 'vue';

import { Plugin1, Plugin2 } from './plugins';

Vue.use(Plugin1, '參數1', '參數2');
Vue.use(Plugin2, '參數A', '參數B');      

然後我們在入口檔案​

​main.js​

​引用這段代碼

// 檔案: src/main.js

import Vue from 'vue';

import '@/classes/vue-use';
import App from './App';
import router from './router';

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
    el: '#app',
    router,
    render: h => h(App),
});      

此時我們執行​

​npm run dev​

​打開8080端口開啟開發調試工具可以看到控制台輸出以下資訊

...]

從中可以發現我們在​

​plugin1​

​​中的​

​install​

​​方法編寫的三個console都列印出來,第一個列印出來的是Vue對象,第二個跟第三個是我們傳入的兩個參數。

而​​

​plugin2​

​​沒有​

​install​

​方法,它本身就是一個方法,也能列印三個參數,第一個是Vue對象,第二個跟第三個也是我們傳入的兩個參數。

那麼現在我們是不是大概對​

​Vue.use​

​有一個模糊的猜想~

分析源碼

好我們還是不要猜想,直接上源碼

// Vue源碼檔案路徑:src/core/global-api/use.js

import { toArray } from '../util/index'

export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    const 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​

​​兩種類型。

對于這兩種類型有不同的處理。

首先将我們傳入的參數整理成數組 => ​​

​const args = toArray(arguments, 1)​

​​。

(toArray源碼)

// Vue源碼檔案路徑:src/core/shared/util.js

export function toArray (list: any, start?: number): Array<any> {
  start = start || 0
  let i = list.length - start
  const ret: Array<any> = new Array(i)
  while (i--) {
    ret[i] = list[i + start]
  }
  return ret
}      

再将​

​Vue​

​​對象添加到這個數組的起始位置​

​args.unshift(this)​

​​,這裡的this 指向​

​Vue​

​​對象

如果我們傳入的​​

​plugin​

​​(Vue.use的第一個參數)的​

​install​

​​是一個方法。也就是說如果我們傳入一個對象,對象中包含​

​install​

​​方法,那麼我們就調用這個​

​plugin​

​​的​

​install​

​​方法并将整理好的數組當成參數傳入​

​install​

​​方法中。 => ​

​plugin.install.apply(plugin, args)​

​​ 如果我們傳入的​

​plugin​

​就是一個函數,那麼我們就直接調用這個函數并将整理好的數組當成參數傳入。 => ​

​plugin.apply(null, args)​

​ 之後給這個插件添加至已經添加過的插件數組中,标示已經注冊過 => ​

​installedPlugins.push(plugin)​

​ 最後傳回Vue對象。

小結

export const Plugin = {
    install(Vue) {
        Vue.component...
        Vue.mixins...
        Vue...
        // 我們也可以在install裡面執行其他函數,Vue會将this指向我們的插件
        console.log(this)  // {install: ...,utils: ...}
        this.utils(Vue)    // 執行utils函數
        console.log(this.COUNT) // 0
    },
    utils(Vue) {
        Vue...
        console.log(Vue)  // Vue
    },
    COUNT: 0    
}
// 我們可以在這個對象上添加參數,最終Vue隻會執行install方法,而其他方法可以作為封裝install方法的輔助函數

const test = 'test'
export function Plugin2(Vue) {
    Vue...
    console.log(test)  // 'test'
    // 注意如果插件編寫成函數形式,那麼Vue隻會把this指向null,并不會指向這個函數
    console.log(this)  // null
}
// 這種方式我們隻能在一個函數中編寫插件邏輯,可封裝性就不是那麼強了