(慕课网)Vue.js源码全方位深入解析
Vue.js源码全方位深入解析¶
基于 Vue2.5.18 源码解析
准备¶
由于视频教程中的 vuejs/vue at v2.5.17-beta.0 (github.com) 版本过旧无法安装依赖,所以这里使用了 2.5.18 版本。 下载源码 vuejs/vue at v2.5.18 (github.com) ,安装 Node.js 环境,并执行一次成功的构建。 Vue2 使用了 Flow 作为类型检查工具,在 Vue3 已经被 TypeScript 取代。
认识目录结构¶
scripts/build.js
构建的入口文件,该文件引入了同目录下 config.js
作为配置,config.js
指定了不同构建版本的入口文件以及输出,可以看到 Vue2 是使用 rollup
构建系统进行构建的。
src/platforms/web/entry-runtime-with-compiler.js
对于网页版本构建的入口,这个Vue包含了运行时和编译器。
src/core/instance/index.js
里面的 Vue 函数是一切的开始,该方法需要通过 new 操作符创建 Vue 实例,在该方法下面使用了一些”mixin“来挂载内置方法,以及实现 Vue 的各种特性。
new Vue 执行了哪些操作¶
观察 src/core/instance/init.js
的 initMixin
函数,该函数对vue进行了一系列初始化操作。
- 在 Vue 函数的 prototype 上挂载
_init
方法 - 提示:startTag/endTag/mark 是统计性能的工具,可以忽略
- 获取 this 对象
- 设置
_uid
- 整合来自构造函数的参数到
$options
- 初始化各种 API:
- 声明周期
- 事件
- 渲染器
- 调用钩子:
beforeCreate
- initInjections
- 初始化状态(#initState)
- initProvide
- 调用钩子:
created
- 如果传入了
$el
则将实例挂载($mount
#mount)到这个节点上
提示:你可以在浏览器版的 vue.js 要调试的地方的增加一行 debugger
进入控制台断点调试。
下面我们来挑选一些初始化过程看。
initState¶
initState
方法用于初始化状态,包括:props
/ methods
/ data
/ computed
/ watch
其中的 initData
函数就是初始化 data
(将 _data
挂载到 vm 实例上)这个函数的核心主要有两点:
- proxy
函数:对 data 中的数据进行代理,读写(set/get)实例的属性同时影响到 vm 实例下 _data
的属性。
- observe
函数:数据的响应式实现。
$mount¶
$mount
方定义了两次:
- src/platforms/web/runtime/index.js
这里定义的是通用的挂载方法,核心函数是:#mountComponent
- src/platforms/web/entry-runtime-with-compiler.js
这里覆盖了上面的挂载方法,并添加了模板编译器:#带模板编译器的mount包装方法
mountComponent¶
这个函数定义于 src/core/instance/lifecycle.js
,执行内容如下
- 进入函数后,首先检查 render 方法,如果没有则创建一个的 vnode,或提示相应的警告
- 调用 beforeMount
钩子
- 创建 updateComponent
函数,其内部调用了 _update
和 _render
(#initRender renderMixin)方法
- 创建一个 Watcher
监听数据变化(应该会立即执行一次 updateComponent
)
带模板编译器的mount包装方法¶
这段代码创建了原始$mount
的副本,并且新建了一个函数覆盖它。
- 获取要挂载到的目标 el 元素
- 如果没有 render 函数的处理:
- 获取 template 的字符串模板
- 渲染 template 模板:执行 compileToFunctions
函数获取 render
/staticRenderFns
方法
- 执行上面保存的 mount
函数
提示:你可以使用 vm.$options.render.toString()
获取 vue 编译 template 产生的 render 函数的代码
下面是一个 render 函数的例子:
initRender&renderMixin¶
initRender 挂载了一些渲染相关的属性和方法。
renderMixin 方法在 vm 实例上挂载了 $nextTick
和 _render
方法。
_render
方法的主要作用就是调用 vm.$options.render
方法
虚拟 DOM¶
由于 HTML 的原生 DOM 节点内容过于庞大,操作和更新的成本较高,我们需要使用结构简单的 #VNode 来代替。
VNode¶
VNode 是一个类,文件在 src/core/vdom/vnode.js
。VNode 的实现借鉴了 snabbdom
。
createElement¶
src/core/vdom/create-element.js
createElement 函数用于创建 VNode。