前言
想学习一个框架的源码最好从初始化流程开始逐步深入,本篇幅主要介绍vue的初始化流程Trust me 绝对完整
建议
本篇幅可能需要阅读大概半个小时左右可以泡上一杯雀巢或者一杯花茶慢慢看,但是我觉得花上一些时间弄懂这些还是值得的
1.github.com/vuejs/vue 可以去这个地址把源码克隆下来


源码下载下来之后需要生成sourcemap映射源码文件 方便我们在浏览器断点调试
1.npm i //下载包的时候如果看到phantom.js终止就可以这个下载特别慢重点是咱们也用不到
2.npm i -g rollup
3.修改dev脚本 "dev": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:webfull-dev"
4.npm run dev
5.之后会看到dist目录下生成了vue.js.map文件
- scripts 文件内有很多命令我们重点关注TARGET的值
- dev命令指向的是
web-full-dev
我们可以全局搜一下 - 这时候应该来到了
scripts/config.js
里面可以从这里开始看


- 扩展
$mount
- 内部判断了vue挂载的优先级 大家都知道 vue挂载有几种方式
render > template > el
就是在这里区分的优先级 - 接下来调用
compileToFunctions
函数将vue模板
转化成render
渲染函数 (内部大概流程是将模板转化成抽象语法树ast之后将ast代码生成为可执行的代码具体细节以后会讲 本次只关心渲染的流程) - 将render函数挂载到options上方便后续调用

- 将
patch
函数挂载到Vue的原型上后面的流程diff
计算的时候会用到该函数 $mount
函数内部执行mountComponent
挂载函数

new Watcher
将更新函数传到watcher中等后续依赖注入完成调用_render渲染函数渲染虚拟dom- 我们继续看
core/index
创建完成之后会回来继续看mountComponent
挂载的过程

- 初始化全局api 例如
use、componet、delete、set、nexttick
等 - 继续往后查找
instance/index

- 在这个函数中我们就看到了
Vue
函数的定义还有其他初始化方法 - 接下来看
initMixin
方法内部干了什么

- 首先初始化
_init
方法也就是外部Vue函数里面调用的 - 函数内部会进行选项合并主要是用户在
new Vue
传进来的选项和Vue
本身的选项做个合并 - 在这里我们看到执行了
$mount
并且是有个判断的vm.$options.el
存在会执行这个挂载,这就证明了在外部new Vue
的时候只要传了el
后面不跟mount也能挂载因为在这个位置还会隐式挂载一次 - 之后我们继续看下面几个初始化的方法
initLifecycle

- 挂载
$paren、$root、$children、$refs
等属性
initEvents

- 挂载
events
事件
initRender

- 挂载
$slots、$createElement
等方法 (我们在使用render
挂载的时候 参数里面的h调用的就是此方法)
initState

- 区分
props> methods> data
设置属性的优先级 - 将数据变为响应式
- 之后调用
initData

- 判断
date
是否是函数还是对象执行不同的操作 - 判断
props
和methods
保证没有重复性 - 调用
proxy
做代理使this可以直接访问到Vue
实例上的属性 - 调用
observe
将数据变为响应式

- 首先会判断当前传进来的变量是否加过响应式加过就返回否则继续执行
- 调用
Observer
类将数据变为响应式并且创建依赖

- 创建一个
Dep
管理当前依赖 (这里我们可以叫大管家dep后续会讲到为什么是大管家) - 区分数组还是对象做不同的响应式处理
- 对象的情况直接调用
walk
方法 - 数组的情况需要判断是否有原型 (老的ie是没有的)
- 在数组有原型的情况直接调
protoAugment
进行原型覆盖(这里主要是为了数组的增删改因为Object.defineProperty在语言层面检测不到数组的变化所以需要自己覆盖下数组的原型使用自己的方法检测
) - 在数组没有原型的情况调
copyAugment
复制一份

- 直接调用walk将数据循环遍历调用defineReactive
- 我们看defineReactive做了些什么操作

- 每创建一个响应式对象,这里就会创建一个
dep
管理当前自己的依赖 这里的dep我们可以看成 小管家dep只管理自己当前的依赖 - 这里就是通过
Object.defineProperty
将数据变成响应式的过程并且和watcher
创建依赖关系 - 到这里依赖就已经注入完成创建完毕了,接下来就会执行
$mount
中的mountComponent
方法 - 我们继续接着上面的
mountComponent
挂载开始讲

- 将更新函数赋值给
updateComponent
new Watcher
将更新函数传到watcher中等后续依赖注入完成调用_render
渲染函数渲染vdom

- 调用
this.get
方法 get
方法内部会执行getter
方法这里的getter
方法也就是Watcher
类接收的第二个参数_render
渲染函数如果是在浏览器打断点调试的话到这里就可以看到页面初始化完成了

dep
内部有几个方法addSub
是将依赖放到当前数组中方便之后notify
进行更新defineReactiv
e中触发的方法的depend
方法就是dep
中的depend
notify
方法就是更新的时候调的批量更新subs
中的依赖就可以(subs中大家看到的update方法是在watcher中关联的时候创建的这里涉及到更新过程之后会讲解)depend
方法的内部Dep.target
指向的就是Watcher
类我们在来看一下watcher
类里面的方法

addDep
方法里面我们可以看到和外面的dep
做了关联保证了以后的更新流程这里就是依赖收集的过程(但是注意依赖收集初始化的时候是不会做的当你用的时候才会触发get
做依赖收集这里只是介绍)

update
方法同步的时候会走run
函数run
函数内部调用的也是get
方法

get
方法内部主要调用的是getter
方法getter
是在new Watcher
的时候传进来的是上面提到的_render
渲染函数


有个问题说明一下 上面提到的大管家dep和小管家dep
1.从Vue函数内部的this._init开始看看this._init具体做了啥
2.之后看initState方法
3.initData方法
4.observe方法
5.Observer类
6.defineReactive方法
7.mountComponent方法
8.Watcher类内部
到这里本篇幅就算结束了之后会有nexttick
、render
函数渲染原理包括全局组件注册过程来袭
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!