Vue实例化过程

vue是一个灵活渐进的mvvm框架,其实际内容可以用 UI=f(State)这个公式来表示。

今天第一篇关于vue的剖析,从其实例化的过程来展开。

vue实例化

vue核心是声明式渲染,其初始化的实例为后面的过程准备了各种条件,看下面一段简单的vue例子:

1
2
3
4
5
6
7
8
9
10
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})

第一段代码是要初始化的template,第二段是实例的真正初始化内容,最终template会被渲染成Hello Vue!

那当执行new Vue(options)时里面到底执行了什么?

实例化流程

实际new Vue(options)是调用了Vue.prototype._init方法:

主要流程有:

merge options

第一个流程先简单剖析下,流程过程主要是初始化实例vm的$options, 把构造函数Vue.options({components:..., directives:..., filters:..., _base:...})和options合并赋值给vm.$options;

1
2
3
4
5
6
7
8
9
10
11
12
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options);
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
);
}

设置代理initProxy(vm)

初始化声明周期initLifecycle(vm)

主要是初始化与vm声明周期有关的值

1
2
3
4
5
6
7
8
9
10
11
12
vm.$parent = parent;
vm.$root = parent ? parent.$root : vm;
vm.$children = [];
vm.$refs = {};
vm._watcher = null;
vm._inactive = null;
vm._directInactive = false;
vm._isMounted = false;
vm._isDestroyed = false;
vm._isBeingDestroyed = false;

initEvents(vm)

初始化事件属性:

1
2
vm._events = Object.create(null);
vm._hasHookEvent = false;

initRender(vm)

初始化render的时候需要的一些属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vm._vnode = null; // the root of the child tree
vm._staticTrees = null; // v-once cached trees
var options = vm.$options;
var parentVnode = vm.$vnode = options._parentVnode; // the placeholder node in parent tree
var renderContext = parentVnode && parentVnode.context;
vm.$slots = resolveSlots(options._renderChildren, renderContext);
vm.$scopedSlots = emptyObject;
// bind the createElement fn to this instance
// so that we get proper render context inside it.
// args order: tag, data, children, normalizationType, alwaysNormalize
// internal version is used by render functions compiled from templates
vm._c = function (a, b, c, d) { return createElement(vm, a, b, c, d, false); };
// normalization is always applied for the public version, used in
// user-written render functions.
vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };

callHook(vm, ‘beforeCreate’)

调用‘beforeCreate’的hook函数var handlers = vm.$options[hook];

initInjections(vm)

对vm.$options中的injections处理

initState(vm)

这个过程非常重要,里面吹了props/methods/data/computed等数据并初始化了依赖、watchers、deps等,是整个vm实例能够渲染并且监听数据变化的关键;

1
2
3
4
5
6
7
8
9
10
11
12
13
vm._watchers = [];
var opts = vm.$options;
if (opts.props) { initProps(vm, opts.props); }
if (opts.methods) { initMethods(vm, opts.methods); }
if (opts.data) {
initData(vm);
} else {
observe(vm._data = {}, true /* asRootData */);
}
if (opts.computed) { initComputed(vm, opts.computed); }
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch);
}

initProvide(vm)

var provide = vm.$options.provide;

callHook(vm, ‘created’)

调用‘created’的hook函数var handlers = vm.$options[hook];

vm.$mount(vm.$options.el)

这个是初始化vue实例的最后一步,把虚拟dom挂载到option.el(即’#app’)中;

以上就是vue实例化的所有流程,本文并没有介绍各个流程的详细处理过程,在后续文章中会一一展开。

vue实例生命周期

从上面流程中,其实可以看出一些实例生命周期的过程:

声明周期