Vue首次渲染做了什么

125 阅读2分钟

1、首先找到Vue的构造函数

源码位置:src\core\instance\index.js

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

options是用户传递过来的配置项,如data、methods等常用的方法

在下面还定义了一些初始化的方法

  // 定义Vue原型上的init方法(内部方法)
  initMixin(Vue);
  // 定义原型上跟数据相关的属性方法
  stateMixin(Vue);
  //定义原型上跟事件相关的属性方法
  eventsMixin(Vue);
  // 定义原型上跟生命周期相关的方法
  lifecycleMixin(Vue);
  // 定义渲染相关的函数
  renderMixin(Vue);

2、_init方法是在initMixin中定义的,所以接下来看到initMixin方法

源码位置:src\core\instance\init.js

export function initMixin (Vue) {
  Vue.prototype._init = function (options) {
    const vm = this
    vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
    )
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')

    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }
}

首先,把Vue实例赋值给变量vm,并且把用户传递的options选项与当前构造函数的options属性及其父级构造函数的options属性进行合并,得到一个新的options选项赋值给$options属性,并将$options属性挂载到Vue实例上,如下:

3、调用mergeOptions函数来进行属性合并

function mergeOptions (parent,child,vm) {
    {
      checkComponents(child);
    }
    if (typeof child === 'function') {
      child = child.options;
    }
    // props,inject,directives的校验和规范化
    normalizeProps(child, vm);
    normalizeInject(child, vm);
    normalizeDirectives(child);

    // 针对extends扩展的子类构造器
    if (!child._base) {
      // extends
      if (child.extends) {
        parent = mergeOptions(parent, child.extends, vm);
      }
      // mixins
      if (child.mixins) {
        for (var i = 0, l = child.mixins.length; i < l; i++) {
          parent = mergeOptions(parent, child.mixins[i], vm);
        }
      }
    }

    var options = {};
    var key;
    for (key in parent) {
      mergeField(key);
    }
    for (key in child) {
      if (!hasOwn(parent, key)) {
        mergeField(key);
      }
    }
    function mergeField (key) {
      // 拿到各个选择指定的选项配置,如果没有则用默认的配置
      var strat = strats[key] || defaultStrat;
      // 执行各自的合并策略
      options[key] = strat(parent[key], child[key], vm, key);
    }
    // console.log(options)
    return options
  }

接着,通过调用一些初始化函数来为Vue实例初始化一些属性,事件,响应式数据等,如下

initLifecycle(vm)       // 初始化生命周期
initEvents(vm)        // 初始化事件
initRender(vm)         // 初始化渲染
callHook(vm, 'beforeCreate')  // 调用生命周期钩子函数
initInjections(vm)   //初始化injections
initState(vm)    // 初始化props,methods,data,computed,watch
initProvide(vm) // 初始化 provide
callHook(vm, 'created')  // 调用生命周期钩子函数

4、调用$mount开启下一生命周期

if (vm.$options.el) {
    vm.$mount(vm.$options.el)
}

在所有的初始化工作都完成以后,最后,会判断用户是否传入了el选项,如果传入了则调用$mount函数进入模板编译与挂载阶段,如果没有传入el选项,则不进入下一个生命周期阶段,需要用户手动执行vm.$mount方法才进入下一个生命周期阶段。