Vue 進階系列(二)之插件原理及實現

(關注福利,關注本公衆號回覆[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導)
html

Vue進階系列彙總以下,歡迎閱讀,歡迎加高級前端進階羣一塊兒學習(文末)。前端

Vue 進階系列(一)之響應式原理及實現 vue

Vue 進階系列(二)之插件原理及實現git

Vue 進階系列(三)之Render函數原理及實現github

使用方法

插件的詳細使用方法詳情看Vue官網面試

Vue官網之插件Plugins

歸納出來就是數組

  • 一、經過Vue.use(MyPlugin)使用,本質上是調用MyPlugin.install(Vue)
  • 二、使用插件必須在new Vue()啓動應用以前完成,實例化以前就要配置好。
  • 三、若是使用Vue.use屢次註冊相同插件,那隻會註冊成功一次。

源碼解讀

Vue.use源碼以下前端工程師

Vue.use = function (plugin) {   
    // 忽略已註冊插件
    if (plugin.installed) {
      return
    }
    
    // 集合轉數組,並去除第一個參數
    var args = toArray(arguments, 1);
    
    // 把this(即Vue)添加到數組的第一個參數中
    args.unshift(this);
    
    // 調用install方法
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args);
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args);
    }
    
    // 註冊成功
    plugin.installed = true;
    return this;
  };

Vue.use接受一個對象參數plugin,首先判斷是否已註冊,若是屢次註冊相同插件那麼只會註冊成功一次,在註冊成功後設置plugin.installed = trueapp

而後執行toArray(arguments, 1)方法,arguments是一個表示全部參數的類數組對象,須要轉換成數組以後才能使用數組的方法。ide

function toArray (list, start) {
  start = start || 0;
  var i = list.length - start;
  var ret = new Array(i);
  // 循環去除 前start元素
  while (i--) {
    ret[i] = list[i + start];
  }
  return ret
}

上面進行了一次轉換,假設list是[1, 2, 3, 4],start是1,首先建立一個包含3個元素的數組,依次執行ret[2] = list[ 2 + 1]ret[1] = list[ 1 + 1]ret[0] = list[ 0 + 1],實際上就是去除arguments的第一個參數而後把剩餘的類數組賦值給新的數組,其實就是去除plugin參數,由於調用plugin.install的時候不須要這個參數。

還能夠經過以下幾種方式實現類數組轉換成數組,可是使用slice會阻止某些JavaScript引擎中的優化(參考自MDN)。

// ES5
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);

// ES6
const args = Array.from(arguments);
const args = [...arguments];

轉換成數組以後調用args.unshift(this),把Vue對象添加到args的第一個參數中,這樣就能夠在調用plugin.install方法的時候把Vue對象傳遞過去。

實例:實現一個插件

要求建立一個告訴Vue組件處理自定義rules規則選項的插件,這個rules須要一個對象,該對象指定組件中的數據的驗證規則。

示例:

const vm = new Vue({
  data: { foo: 10 },
  rules: {
    foo: {
      validate: value => value > 1,
      message: 'foo must be greater than one'
    }
  }
})

vm.foo = 0 // 輸出 foo must be greater than one

第一步先不考慮插件,在已有的VueAPI中是沒有rules這個公共方法的,若是要簡單實現的話能夠經過鉤子函數來,即在created裏面驗證邏輯。

const vm = new Vue({
    data: { foo: 10 },
    rules: {
        foo: {
          validate: value => value > 1,
          message: 'foo must be greater than one'
        }
    },
    created: function () {
      
        // 驗證邏輯
        const rules = this.$options.rules
        if (rules) {
          Object.keys(rules).forEach(key => {
          
            // 取得全部規則
            const { validate, message } = rules[key]
            
            // 監聽,鍵是變量,值是函數
            this.$watch(key, newValue => {
            
              // 驗證規則
              const valid = validate(newValue)
              if (!valid) {
                console.log(message)
              }
            })
          })
        }
      }
    
})

能夠經過this.$options.rules獲取到自定義的rules對象,而後對全部規則遍歷,使用自定義的validate(newValue)驗證規則。

第二步實現這個rules插件,爲了在Vue中直接使用,能夠經過Vue.mixin注入到Vue組件中,這樣全部的Vue實例均可以使用。

按照插件的開發流程,應該有一個公開方法install,在install裏面使用全局的mixin方法添加一些組件選項,mixin方法包含一個created鉤子函數,在鉤子函數中驗證this.$options.rules

實現代碼以下:

import Vue from 'vue'

// 定義插件
const RulesPlugin = {

  // 插件應該有一個公開方法install
  // 第一個參數是Vue 構造器
  // 第二個參數是一個可選的選項對象
  install (Vue) {
  
    // 注入組件
    Vue.mixin({
    
      // 鉤子函數
      created: function () {
      
        // 驗證邏輯
        const rules = this.$options.rules
        if (rules) {
          Object.keys(rules).forEach(key => {
          
            // 取得全部規則
            const { validate, message } = rules[key]
            
            // 監聽,鍵是變量,值是函數
            this.$watch(key, newValue => {
            
              // 驗證規則
              const valid = validate(newValue)
              if (!valid) {
                console.log(message)
              }
            })
          })
        }
      }
    })
  }
}

// 調用插件,實際上就是調用插件的install方法
// 即RulesPlugin.install(Vue)
Vue.use(RulesPlugin)

參考

Vue官網之插件Plugins
MDN之Arguments 對象

交流

本人Github連接以下,歡迎各位Star

http://github.com/yygmind/blog

我是木易楊,網易高級前端工程師,跟着我每週重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!

若是你想加羣討論每期面試知識點,公衆號回覆[加羣]便可

相關文章
相關標籤/搜索