Vue源碼分析(3)--選項(xiàng)合并過(guò)程mergeOptions

前言

本文是vue2.x源碼分析的第三篇,主要講解選項(xiàng)合并過(guò)程mergeOptions!

先看調(diào)用形式

vm.$options = mergeOptions(
    resolveConstructorOptions(vm.constructor),
    options || {},
    vm
);

1、執(zhí)行resolveConstructorOptions(vm.constructor)

function resolveConstructorOptions (Ctor) {
  var options = Ctor.options; //Ctor即Vue$3,Vue$3.options是在第一節(jié)中通過(guò)extend函數(shù)賦值的
  if (Ctor.super) {  //這里由于沒(méi)有super屬性,故直接返回了options
    var superOptions = resolveConstructorOptions(Ctor.super);
    var cachedSuperOptions = Ctor.superOptions;
    if (superOptions !== cachedSuperOptions) {
      // super option changed,
      // need to resolve new options.
      Ctor.superOptions = superOptions;
      // check if there are any late-modified/attached options (#4976)
      var modifiedOptions = resolveModifiedOptions(Ctor);
      // update base extend options
      if (modifiedOptions) {
        extend(Ctor.extendOptions, modifiedOptions);
      }
      options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions);
      if (options.name) {
        options.components[options.name] = Ctor;
      }
    }
  }
  return options
}

返回的options長(zhǎng)這個(gè)樣子:

options = {
    components: {
        KeepAlive,
        Transition,
        TransitionGroup
    },
    directives: {
        model,
        show
    },
    filters: {},
    _base: Vue
}

2、執(zhí)行mergeOptions (parent,child,vm)

parent即上述返回的options,child即new Vue(options)傳入的options

function mergeOptions (parent,child,vm) {
  {
    //檢查傳入的components選項(xiàng)的名字是否符合規(guī)定(非內(nèi)置標(biāo)簽)
    checkComponents(child);
  }
  //將傳入的child.props轉(zhuǎn)換為駝峰式結(jié)構(gòu)的對(duì)象表達(dá)形式.props能使用數(shù)組和對(duì)象語(yǔ)法,
但在內(nèi)部都會(huì)重新遍歷封裝到一個(gè)新對(duì)象中。
  normalizeProps(child);
  //directives使用對(duì)象語(yǔ)法,對(duì)象中屬性的值只能為函數(shù),該操作會(huì)將函數(shù)綁定到指令的bind和update函數(shù)上
  normalizeDirectives(child);
  //若存在extends,則將其內(nèi)容合并到父對(duì)象parent中保存,最后再和自身child合并,extends最好是對(duì)象語(yǔ)法
  var extendsFrom = child.extends; //暫不清楚作用,記為Unknown3.1
  if (extendsFrom) {
    parent = typeof extendsFrom === 'function'
      ? mergeOptions(parent, extendsFrom.options, vm)
      : mergeOptions(parent, extendsFrom, vm);
  }
  //若存在mixins,則將其內(nèi)容合并到父對(duì)象parent中保存,最后再和自身child合并,mixins只能是數(shù)組語(yǔ)法,數(shù)組中元素可以是對(duì)象
  if (child.mixins) {
    for (var i = 0, l = child.mixins.length; i < l; i++) {
      var mixin = child.mixins[i];
      if (mixin.prototype instanceof Vue$3) {
        mixin = mixin.options;
      }
      parent = mergeOptions(parent, mixin, vm);
    }
  }
  //初始化一個(gè)對(duì)象,用于存儲(chǔ)parent和child合并后的內(nèi)容,并作為mergeOptions函數(shù)的結(jié)果返回
  var options = {};
  var key;
  for (key in parent) {
    mergeField(key);
  }
  for (key in child) {
    if (!hasOwn(parent, key)) {
      mergeField(key);
    }
  }
  //使用策略對(duì)象對(duì)parent和child進(jìn)行合并
  function mergeField (key) {
    var strat = strats[key] || defaultStrat;
    options[key] = strat(parent[key], child[key], vm, key);
  }
  return options
}

2.1、分析checkComponents(child)

function checkComponents (options) {
  for (var key in options.components) {//對(duì)象遍歷形式,故components選項(xiàng)只能用對(duì)象,不用數(shù)組
    var lower = key.toLowerCase();
    //組件名字不能是內(nèi)置標(biāo)簽(slot,component)和保留標(biāo)簽(html標(biāo)簽和svg標(biāo)簽),用了閉包實(shí)現(xiàn)
    if (isBuiltInTag(lower) || config.isReservedTag(lower)) {
      warn(
        'Do not use built-in or reserved HTML elements as component ' +
        'id: ' + key
      );
    }
  }
}

2.2、分析normalizeProps(child);

function normalizeProps (options) {
  var props = options.props;
  if (!props) { return }
  var res = {};
  var i, val, name;
  if (Array.isArray(props)) { //props是數(shù)組
    i = props.length;
    while (i--) {
      val = props[i];
      if (typeof val === 'string') {
        name = camelize(val);//若val是*-i*的形式,則將其轉(zhuǎn)為*I*,如v-header會(huì)被轉(zhuǎn)為vHeader并被緩存
        res[name] = { type: null }; //每個(gè)val的值設(shè)為含有type屬性的對(duì)象
      } else {
        warn('props must be strings when using array syntax.');
      }
    }
  } else if (isPlainObject(props)) {//props是對(duì)象
    for (var key in props) {
      val = props[key];
      name = camelize(key);
      res[name] = isPlainObject(val)//若用對(duì)象語(yǔ)法,則每個(gè)key的value對(duì)象最好包含type屬性
        ? val
        : { type: val };
    }
  }
  options.props = res;
}

// 調(diào)用前:options.props=['header-value'];
// 調(diào)用后:options.props={
//           'headerValue':{type:null}
//         }

2.3、分析normalizeDirectives(child)

function normalizeDirectives (options) {
  var dirs = options.directives;
  if (dirs) {
    for (var key in dirs) { //數(shù)組也可以用for in遍歷,故directives選項(xiàng)能用對(duì)象和數(shù)組語(yǔ)法,當(dāng)只關(guān)心數(shù)組的value而不關(guān)心key時(shí)可以用for in遍歷
      var def = dirs[key];
      if (typeof def === 'function') {
        dirs[key] = { bind: def, update: def };
      }
    }
  }
}
// 調(diào)用前:options.directives={
//            v-focus:function some(){}
//         };
// 調(diào)用后:options.directives={
//           'v-focus':{
//               bind:some,
//               update:some
//           }
//         }

2.4、分析extends和mixins

??二者作用都是進(jìn)一步豐富parent選項(xiàng),其本身是調(diào)用mergeOptions,這里不做分析,注意mixins只能用數(shù)組語(yǔ)法

2.5、分析合并策略對(duì)象strats

  • 10個(gè)生命周期函數(shù)--mixins中同名屬性用數(shù)組保存,mixins中的優(yōu)先級(jí)高,先調(diào)用,
    合并后類似這樣:

    beforeCreate:[mixins中的beforeCreate,child中的beforeCreate]
    
  • 3個(gè)assets(directives、components、filters)--繼承策略,以parent中同名屬性的值為原型對(duì)象,以child中同名屬性的值做實(shí)例屬性,指令合并后類似這樣:

    directives:{'v-focus':obj1,__proto__:{model:obj2,show:obj3}}
    
  • el與propsData、也是用defaultStrat函數(shù),只是會(huì)先判斷vm實(shí)例是否存在

  • data 返回一個(gè)函數(shù)mergedInstanceDataFn

  • watch 同生命周期函數(shù)的合并策略

  • props與methods與computed 覆蓋策略,mixins中的同名屬性會(huì)被child覆蓋
    props合并后類似這樣:

    props:[child中的屬性]
    
  • 其余選項(xiàng)的合并策略采用defaultStrat函數(shù)

3、小結(jié)

  • 下一步分析內(nèi)容
    ? 主要執(zhí)行過(guò)程-2(實(shí)例的初始化過(guò)程)
    ? 主要執(zhí)行過(guò)程-3(依賴收集、組件掛載等過(guò)程)
  • 遺留問(wèn)題解決情況
    ? Unknown3.1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容