Vue从入门到精通

vue源码阅读——合并options

2017-11-16  本文已影响3466人  丨ouo丨

vue里面,我们是可以自己传一些数据进去的。比如说

var vm = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue!'
      }
})

像这种的话,我们在new Vue的时候传了一个对象。就是

{
      el: '#app',
      data: {
        message: 'Hello Vue!'
      }
}

那么其实我们新建的这个Vue实例,会在代码运行后增加很多新的东西进去。我们把我们传入的这个对象叫options,这篇博客主要讲的就是关于vm.$options这个属性,这个属性在vue整个框架中都是不断出现的。所以弄清楚vm.$options对于源码阅读也十分有裨益。

先上一个随心所欲的图



下面一步步讲~
首先我们要找vm.$options最开始是在哪里出现的。在initMixin这个函数里面最早出现vm.$options的定义。

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

我们结合图看,mergeOptions主要分成两块,就是resolveConstructorOptions(vm.constructor)optionsmergeOptions这个函数的功能就是要把这两个合在一起。
options是我们自己写代码的时候传进去的,
因此需要看看的就是resolveConstructorOptions这一块。resolveConstructorOptions这个函数主要就是返回构造函数里面的options。

  1. resolveConstructorOptions
export function resolveConstructorOptions (Ctor: Class<Component>) {
  let options = Ctor.options
  if (Ctor.super) {
    const superOptions = resolveConstructorOptions(Ctor.super)
    const 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)
      const 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和父类的options合起来。

  1. mergeOptions
export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {
  if (process.env.NODE_ENV !== 'production') {
    checkComponents(child)
  }

  if (typeof child === 'function') {
    child = child.options
  }

  normalizeProps(child, vm)
  normalizeInject(child, vm)
  normalizeDirectives(child)
  const extendsFrom = child.extends
  if (extendsFrom) {
    parent = mergeOptions(parent, extendsFrom, vm)
  }
  if (child.mixins) {
    for (let i = 0, l = child.mixins.length; i < l; i++) {
      parent = mergeOptions(parent, child.mixins[i], vm)
    }
  }
  const options = {}
  let key
  for (key in parent) { // 遍历Vue.options对象的属性
    mergeField(key)
  }
  for (key in child) { // 遍历options对象的属性
    if (!hasOwn(parent, key)) {
      mergeField(key)
    }
  }
  function mergeField (key) { // 每个key都会对应在strats中初始化好的函数
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key)
  }
  return options
}
  1. vm.constructor里面主要有哪些options:components,directives,filters,还有一个_base用来指向构造函数自身。initGlobalAPI这个函数中有许多初始化构造函数的代码,给构造函数添加options就在其中。可以看看初始化的代码:
function initGlobalAPI (Vue) {
  // config
  var configDef = {};
  configDef.get = function () { return config; };
  if (process.env.NODE_ENV !== 'production') {
    configDef.set = function () {
      warn(
        'Do not replace the Vue.config object, set individual fields instead.'
      );
    };
  }
  Object.defineProperty(Vue, 'config', configDef);

  // exposed util methods.
  // NOTE: these are not considered part of the public API - avoid relying on
  // them unless you are aware of the risk.
  Vue.util = {
    warn: warn,
    extend: extend,
    mergeOptions: mergeOptions,
    defineReactive: defineReactive
  };

  Vue.set = set;
  Vue.delete = del;
  Vue.nextTick = nextTick;

  Vue.options = Object.create(null);  // 这里开始
  ASSET_TYPES.forEach(function (type) { // 添加components,directives,filters
    Vue.options[type + 's'] = Object.create(null);
  });

  // this is used to identify the "base" constructor to extend all plain-object
  // components with in Weex's multi-instance scenarios.
  Vue.options._base = Vue; // 指向Vue本身的 _base 

  extend(Vue.options.components, builtInComponents); // 把builtInComponents里面的属性添加到Vue.options.components里面

  initUse(Vue);
  initMixin$1(Vue);
  initExtend(Vue);
  initAssetRegisters(Vue);
}
上一篇下一篇

猜你喜欢

热点阅读