本小节将解析当我们使用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.options
1
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
的良好的代码结构和命名规范,这也是今后可以学习的地方