vue3源码主要分为三大块:编译系统、响应式系统、运行时系统。编译系统就是将template模板编译成为渲染函数;响应式系统就是监听响应式数据;运行时系统就是负责渲染,将虚拟节点渲染成为真正的dom元素并且显示在浏览器端。
具体来说:
一、响应式系统:实现了响应式对象的创建、依赖收集、依赖触发
二、编译系统:实现了如何将一个模板转换为render函数
三、运行时系统:实现了虚拟DOM转换为真实DOM,并且通过diff算法对比VNode
首先说说响应式系统:
响应式对象的创建
响应式对象是通过proxy来进行创建的,相对比DefineProperty功能更加强大,对于新增对象的监测以及数组的监测功能会更强大。在vue中提供了2个核心的创建响应式变量的方法:ref,reactive , 建议创建基本类型的响应式对象可以使用ref,创建对象类型的响应式对象使用reactive。- ref
在源码中,主要是通过RefImpl函数进行创建,在其构造函数中,保存了两个值,一个原始值;一个响应式的值。响应式的值是通过toReactive来进行判断的,如何是对象则通过reactive来进行构建,否则直接返回value。在RefImpl是一个class,通过其Setter与Getter来实现数据劫持,进而实现track与trigger。
- reactive
在源码中调用createReactiveObject函数进行响应式对象的创建,改函数是通过new Proxy(target,handler)来实现的,reactive可以传递集合的值以及普通类型的值,这两种值分别对应的是collectionHandlers以及baseHandlers。在BaseReactiveHandler中,重写了get函数,通过Reflect.get来获取值(针对特殊状态值、数组、浅层响应式对象、对象等返回不同的数据类型),当当前对象非只读的时候调用了track来进行依赖收集。
MutableReactiveHandler继承了BaseReactiveHandler,重写了set、has、deleteProperty、ownKeys函数,在set函数中通过Reflect.set设置值(针对ref值,新增/更新的值进行特殊处理)
为了使数组也可以实现依赖收集和依赖触发,为了解决数据劫持是惰性的问题以及数组操作爆栈问题,vue3在createArrayInstrumentations重写了数组中的方法,includes、indexOf、lastIndexOf; push、pop、shift、unshift、slice;
- 依赖收集
先说一下数据结构,targetMap<target,key2depmap>, key2depmap<key, depMap>, depMap(effect,number)
通过track函数进行依赖收集,将副作用添加到dep中。按照target-keys-effects结构存储起来 - 依赖触发
通过trigger函数进行依赖的出发,找到对应的target-keys-effects来遍历执行。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。