本文章主要针对的是2.0版本的初始化流程,会结合源码和绘图的方式,加深自己对vue原理的掌握。
new Vue 发生了什么
我们知道,new 关键字在Javascript中代表实例化是一个类,而Vue实际上是一个类,让我们来看一下内部的实现:
代码位置: src/core/instance/index.js
先贴流程图:
可以看到,Vue 的构造函数还是通过ES5的方式来实现的,这样做的好处是方便扩展,通过调用不同的mixin方法,在**Vue.prototype**上添加各类原型方法。
initMixin 方法为Vue添加了 _init 方法,在new Vue的时候会执行该方法,稍后重点分析。
stateMinxin 方法为Vue添加了 $set $delete **$watch**等api。
eventsMinxin 方法为Vue添加了 $emit **$on$off$once**等和事件相关的api。
lifecycleMinxin 方法为Vue添加了**_update (实际会执行patch方法,虚拟dom渲染成真实dom),另外还有$destroy、$forceUpdate(强制组件渲染)、mountComponent(组件挂载)**
renderMixin 方法为Vue添加了**$nexttick,_render(把template编译成render function,最后生成Vnode**)。
好处: 通过把不同的功能逻辑拆成一些单独的函数执行,让主线程逻辑一目了然,代码逻辑十分清晰。
探索_init方法
代码位置: src/core/instance/init.js
先贴流程图:
以上是_init内部的函数执行流程,主要干了以下几件事:
1. 定义组件实例
2. 初始化生命周期
3.初始化事件中心
4. 初始化渲染
5.初始化state(响应式核心)
6.判断用户有没有传el选项,有el开始执行$mount挂载流程
探索挂载逻辑
由于vue提供了不同的版本,一个是Runtime版本,一个是Runtime+compiler版本。两者区别如下:
- Runtime Only版本
通过借助webpack的vue-loader把.vue文件编译成可执行的 Javascript 函数,在编译阶段就执行。所以这个版本只包含运行时的Vue代码,更轻量,体积更小。
- Runtime + Compiler版本
不会对代码进行预编译,如果在配置项中写了 template 选项 ,内部在运行时进行代码编译,把template编译成**render**函数,该版本包含编译代码,包体积更大,推荐使用Runtime only版本。
new Vue({ // 需要编译
template: '<div>{{ hi }}</div>'
})
new Vue({ // 不需要编译
render (h) {
return h('div', this.hi)
}
})
基于上面提到的两个不同版本,我们找到了**$mount**的入口,代码位置: src/platforms/web/entry-runtime-with-compiler.js
先贴流程图:
开始挂载: mountComponent
代码位置: src/core/instance/lifecycle.js
先贴流程图:
核心逻辑其实还是在**watcher内部,watcher**作为响应式的核心是非常重要的。updateComponent在组件初始化和更新的时候都会被执行,_render和_update依次被执行,后面我们会重点分析_render和_update内部具体做了哪些工作。
最后拿**vue**官网的生命周期图来和上述的分析流程做一个对比,加深自己对vue生命周期的理解和掌握:
更新逻辑和销毁逻辑后续再补充,祝大家学习愉快,吃透vue原理。