vue探究:vue component 與 extend

Vue component與Vue extend

爲何要了解vue註冊組件原理

在思考表單集成方案的時候,咱們知道,在配置json生成form組件的時候,總會經過type與form組件一一對應來找到對應的組件,也就是說,在聲明json form類型以前,須要提早開發對應的組件,或者動態掛載組件。在vue框架下,想要作到持續集成,能夠將組件聲明爲全局組件,而後在json轉化爲組件時候經過name來加載對應組件。但這樣作的缺陷是,沒法動態給第三方組件掛載公共的屬性與事件;在設計上看,將擴展組件的功能收斂至統一入口,再借助vue動態實例化組件的能力,這樣作有利於後續持續集成,減小開發上的反作用,使整個庫的開發思路可控。vue

Vue.extend

Vue.extend(extendOptions)json

經過調用vue.extend可返回一個vue的子類緩存

function extend(extendOptions){
    extendOptions = extendOptions || {}
    // this->vue
    const Super = this
    const SuperId = Super.cid
    // 使用父類的id做爲緩存的key
    // 只要父類id相同,每次調用會返回相同的子類
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }   
    // 對name命名方式進行校驗
    // /^[a-zA-Z][\w-]*/
    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
      // vue._init
      this._init(options)
    }
    // 繼承父類構造函數
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    // 合併父類的options
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super

    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    // 初始化props
    // 將props掛載在原型對象的_props屬性下
    if (Sub.options.props) {
      initProps(Sub)
    }
    // 初始化computed
    // 將初始化computed掛載在原型對象下
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    // 複製父類的靜態方法
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
      Sub.options.components[name] = Sub
    }

    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have // been updated. Sub.superOptions = Super.options Sub.extendOptions = extendOptions Sub.sealedOptions = extend({}, Sub.options) // cache constructor cachedCtors[SuperId] = Sub return Sub } } 複製代碼

首先,同直接調用vue構造函數實例化組件來對比,vue.extend在開始先作來一層緩存校驗,若是該extendOptions已經存在組件的構造函數,那麼會直接返回該構造函數,避免同一個組件反覆構建組件生成器函數,同時使用父類的id做爲緩存標時。bash

當未命中緩存時,會進入建立組件生成器函數的過程,首先對組件名稱進行校驗,名稱首字母開頭必須是大小寫英文,後續字符支持大小寫下劃線(_)及間隔線(-)。框架

名稱校驗經過後,先聲明一個組件對構造函數:函數

const Sub = function VueComponent (options) {
  // Vue.prototype._init
  this._init(options)
}
複製代碼

讓Sub函數經過原型繼承父類(Vue),並將傳入的extendOptions與父類的options配置項進行合併,而後保存父類的構造函數至super屬性。ui

options中掛載propscomputed等屬性時,須要單獨進行處理,處理的內部細節與結果在後續的vue探究文章再作深刻討論。this

當經過原型繼承父類,初始化propscomputed成員屬性以後,還須要繼承父類的靜態方法,如mixin、extend、use、component、directive、filter等。spa

最後在子類構造函數上新增superOptions、extendOptions、sealedOptions以備實例化的時候使用,再緩存該新生成子類(組件構造函數)。prototype

總的來看,vue.extend方法本質是建立了一個Sub函數,並繼承了父類(父組件或者Vue構造函數)的相關屬性或者方法。

Vue.component

調用component註冊一個局部或者全局組件,並設置組件的別名。

// 在Vue中,component、filter、directive是混合在一塊兒實現的,這裏拆開
Vue.options['component'] = Object.create(null)

Vue.component = function(id, definition){
    if(!definition){
        return this.options['components'][id]
    }else{
        if(isPlainObject(definition)){
            definition.name = definition.name || id
            definition = Vue.extend(definition)
        }
        this.options['components'][id] = definition
        return definition
    }
}
複製代碼

component方法本質是調用extend方法構造一個子類,並將該子類保存在options的components的對應的key下面,在SFC中註冊的。

文章內容若有錯誤,敬請諒解,但願能夠不吝賜教

轉載請註明出處

相關文章
相關標籤/搜索