本小节将解析当我们使用new Vue的时候,Vue做了哪些事情
new Vue()
1 | <div id="app">{{test}}</div> |
这就是我们使用Vue的基本姿势,上面代码最终会被渲染为如下dom:
1 | <div id="app">1</div> |
当我们修改test的值时dom也会随之变化
上篇文章说过,Vue构造函数定义在src/core/instance/index.js中
1 | function Vue (options) { |
当我们实例化Vue的时候,执行了一句代码this._init(options),其中的options就是我们传入的配置,如el data等选项
_init方法是在执行initMixin方法是被添加到prototype上的方法,所以方法定义在src/core/instance/init.js中
1 | Vue.prototype._init = function (options?: Object) { |
注释是本节例子大概走的流程,在后面一系列初始化的方法中,都有使用到实例的$options属性,$options属性是由mergeOptions返回的,所以我们先看一下mergeOptions
上面在调用mergeOptions时传入了三个参数
resolveConstructorOptions(vm.constructor)此时就是Vue.options1
2
3
4
5
6
7
8
9
10
11
12
13Vue.options = {
components: {
KeepAlive
Transition,
TransitionGroup
},
directives:{
model,
show
},
filters: Object.create(null),
_base: Vue
}options{el: '#app', data: {test: 1}}vm当前Vue实例
mergeOptions
方法定义在core/util/options.js
1 | /** |
简单来说mergeOptions就是对我们传入的参数做个规范化并且和Vue基本的配置根据不同的合并逻辑进行合并,最终会放在$options属性上
继续看_init方法
1 | /* istanbul ignore else */ |
接下来的这段,在生产环境下会将vm._renderProxy的值设置为当前Vue实例。
生产环境和非生产环境的功能应该是要保持一致的,虽然现在还不知道initProxy是什么,但是它的作用应该是于下面的分支一样,只是在开发中给我们提供更多的信息
实际上initProxy方法会使用Proxy去拦截vm对象,在我们访问实例上的属性发生错误时可以提供更加友好的提示
继续
1 | vm._self = vm |
接下来又是一系列的init,从名称也能看出来,初始化生命周期、事件、渲染…
其中callHook函数就是调用声明周期的函数,此处可以发现,调用beforCreate钩子之后才执行initState,这也说明了为什么我们不能在beforCreate的时候访问到data
最后
1 | if (vm.$options.el) { |
最终执行$mount方法,渲染生成好的DOM替换我们传入的节点
总结
其实Vue和我们平时使用类去封装功能并没有什么不同,就执行了一个_init方法,主要对我们传入的配置进行规范,然后将dom生成并渲染到页面
上面所说的都是很大概的流程,vue在其中做了很多事,$mount也不是一句话就能说清楚的,以后会在记录$mount涉及的相关知识点
如果不关心其中每个函数的细节,new Vue的过程还是很好理解的,这也要归功于Vue的良好的代码结构和命名规范,这也是今后可以学习的地方