虽然我们引入了 vue 但是却还没使用(初始化过程),使用的方式就是通过 new Vue 实例化。所以我们要知道 new Vue 的时候都做了哪些事情(首次渲染过程)?

    在源码 src/core/instance/index.js 中,Vue 是通过 Function 的方式定义了一个构造函数,而不是直接使用 ES6Class 定义,主要是为了方便在原型上挂载一些属性和方法。

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

    可以看到 Vue 只能通过 new 关键字初始化,然后会调用 this._init 方法(主要用来在其原型上挂载一些属性和方法),该方法在 src/core/instance/init.js 中定义。

    1. Vue.prototype._init = function (options?: Object) {
    2. const vm: Component = this;
    3. // merge options
    4. if (options && options._isComponent) {
    5. initInternalComponent(vm, options);
    6. } else {
    7. vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options || {}, vm);
    8. }
    9. // expose real self
    10. vm._self = vm;
    11. initLifecycle(vm);
    12. initEvents(vm);
    13. initRender(vm);
    14. callHook(vm, 'beforeCreate');
    15. initInjections(vm); // resolve injections before data/props
    16. initState(vm);
    17. initProvide(vm); // resolve provide after data/props
    18. callHook(vm, 'created');
    19. if (vm.$options.el) {
    20. vm.$mount(vm.$options.el);
    21. }
    22. };

    这里主要列举一些关键的代码,其他的就不一一列举了。Vue 首次渲染过程( Vue.prototype._init )主要包含以下操作。

    1. 将 vue 内置的 options 和用户传入的 options 进行合并

      1. vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options || {}, vm);
    2. 初始化生命周期,给 Vue 实例添加静态属性,$parent、$root、$children、$refs

      1. initLifecycle(vm);
    3. 初始化事件中心

      1. initEvents(vm);
    4. 初始化 render 函数,给 Vue 实例添加静态属性,$vnode、$slots、$scopedSlots、_c、$createElement。添加响应式属性 $attrs、$listeners

      1. initRender(vm);
    5. 调用生命周期钩子函数 beforeCreate

      1. callHook(vm, 'beforeCreate');
    6. data、props 初始化之前接收 inject

      1. initInjections(vm); // resolve injections before data/props
    7. 初始化 props、methods、data、computed、watch

      1. initState(vm);
    8. data、props 之后定义 provide

      1. initProvide(vm); // resolve provide after data/props
    9. 调用生命周期钩子函数 created

      1. callHook(vm, 'created');
    10. vue 实例挂载

      1. if (vm.$options.el) {
      2. vm.$mount(vm.$options.el);
      3. }

    Vue 的初始化逻辑写的非常清楚,把不同的功能逻辑拆成一些单独的函数执行。

    我们的目标是弄清楚模板和数据如何渲染成最终的 DOM,所以各种初始化逻辑我们先不看。在初始化的最后,检测到如果有 el 属性,则调用 vm.$mount 方法挂载 vm(调用完后页面就会渲染出来 Hello Vue !),挂载的目标就是把模板渲染成最终的 DOM