# vue3-core **Repository Path**: soulkey3/vue3-core ## Basic Information - **Project Name**: vue3-core - **Description**: 从0-1手写一个vue3源码; 参考https://www.bilibili.com/video/BV1Q3411w7SQ?p=3&vd_source=b84fcf3480c4220583e0542b1a7a44ae学习 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-07-10 - **Last Updated**: 2022-10-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: vue3, Pnpm ## README # vue3-core #### 介绍 从0-1手写一个vue3源码 # 响应式模块(TODO...) ### 0.index.ts 入口函数,抛出模块方法 ### 1.reactive.ts 响应式入口函数 1. **reactive** 入口主函数。传入参数,判断是否是对象(reactive只能接收对象类型),是否响应式,是否重复传入。都满足通过proxy代理; 2. **WeakMap** 维护一个弱引用的map,用于判断是否重复代理。key: 传入对象。value: 代理对象 3. **isReactive** 判断是否事响应式类型 ### 2.baseHandler.ts 具体的代理函数。业务逻辑的入口 1. **get** 拦截中需要依赖收集。track(target, key, receiver) 2. **set** 触发更新依赖收集中的更新 ### 3.effect.ts 1. **effect** 入口函数。首先会new一个**activeEffect**对象 并且对传入的回调函数执行一次。 2. **activeEffect** 常量用来记录当前作用域正在执行的的**ReactiveEffect**对象 3. **ReactiveEffect** 承载effect主要功能对象。包含**run**执行方法和**stop**停止依赖收集方法 4. **track** 依赖收集。对应在baseHandler.ts--get拦截器中进行依赖收集。 通过weakMap维护effect与数量的对应关系(防止内存泄漏,key为原始对象target) 全流程需要去重 ```javascript // 记录 目标对象对应的key值,所对应的ReactiveEffect对象 WeakMap = { targtet: Map(key: Set(effect1,effect2...)) } // depsMap = Map(2){'name' => Set(1), 'age' => Set(0)} ``` 5. **trackEffects** 衔接track,用于收集effect放入set 6. **trigger** 对应baseHandler.ts--set拦截器中触发更新操作,找出属性依赖的effects取执行更新。 7. **trackEffects** 衔接trigger函数,执行依赖收集完成的每一个effect的run方法 8. **cleanupEffect** 清除属性对应的effect操作。作用: - 需要在执行用户函数之前将之前收集的内容清空。 - effect被删除也需要清除对应的依赖收集,因为不需要再执行了。 9. # runtime-dom模块(TODO...) ### 0. index.ts——入口方法。 合并DOM的操作和修改属性的方法。生成renderOptions对象 ### 1. nodeOps.ts——提供各种DOM操作的API ### 2. patchProp.ts——修改元素的属性操作API - 修改类名--**patchClass** - 修改style--**patchStyle** - 修改事件--**patchEvent** - 普通属性--**patchAttr** ### 3. modules存放patchProp.ts中各种对el属性的具体操作函数 #### 3.1 class.ts 修改类名的方法 #### 3.2 style.ts 修改样式的方法 #### 3.3 event.ts 修改事件的方法 #### 3.4 attr.ts 修改普通属性的方法 # runtime-core模块(TODO...) ### 1. h.ts 生成虚拟DOM的顶层函数 处理各种用户传参的情况,真实的创建方法交给vnode.ts处理 ### 2. vnode.ts 创建虚拟节点 1. **createVnode** 创建虚拟节点函数 ```javascript const vnode = { // 虚拟节点 本质上就是一个对象 type, // h1 span... props, // 属性 class style Onclick... children, // 孩子 el: null, // 虚拟节点对应的真实节点, key: props?.['key'], __v_isVnode: true, shapeFlag // 虚拟节点的类型 数组or文本 } ``` 2. **isVnode** 判断是否是虚拟节点 3. **isSameVnode** 判断两个虚拟节点是否相同。依据type和key 4. **Fragment** 片段标记 5. openBlock 6. createElementBlock 7. setupBlock 8. toDisplayString ### 3. renderer.ts 渲染函数 1. **render **判断卸载还是更新 2. **patch **页面渲染核心方法。参数(n1: 老虚拟节点, n2: 新虚拟节点, container: 容器)。n1为null,表示是创建节点,初始化流程。 3. **processElement** 分流方法,元素创建or更新 4. **mountElement** 初次渲染,挂载真实DOM 5. **mountChildren **递归渲染孩子节点 6. **processText** 插入文本子节点 7. **normalize** 将字符串转换成文本节点 8. **unmount** 卸载 将DOM节点删掉 9. **patchElement** 比较元素。先复用节点,比较属性-》比较子节点 10. **patchProps** 比较属性 11. **patchChildren** 比较孩子差异 ```ja // 文本 空的null 数组 // 比较两个儿子列表差异 // 老 新 // 数组 文本 (删除老儿子,设置文本内容) // 文本 文本 (更新文本) // 数组 数组 (diff算法) // 文本 数组 (清空文本,进行挂载) // 数组 空 (删除所有儿子) // 文本 空 (清空文本) ``` 12. **unmountChildren** 卸载孩子节点[1cCEYMDANgc.png (728×351) (40017.cn)](https://pic5.40017.cn/i/ori/1cCEYMDANgc.png) 13. **patchKeyedChildren** 比对孩子节点——**diff**算法 [1cCEYMDANgc.png (728×351) (40017.cn)](https://pic5.40017.cn/i/ori/1cCEYMDANgc.png) * 定义头指针i,e1指向老子节点尾,e2指向新子节点尾 * 从头开始,一样的节点就复用递归path(sync from start) * 从结尾开始,一样的节点就复用递归path(sync from end) * 如果有一方结束,i >e1 新节点数>老节点数,新增i 到 e2节点; * i > e2,老节点数>新节点数,卸载i到e1节点 * *************优化结束************* * 乱序比较开始 * s1和s2指向乱序的开始 * 建立keyToNewIndexMap记录下key对应的新坐标 * 遍历老的节点,通过key去找在新节点中的索引。如果undefined,需要卸载这个老节点;如果有需要path这个节点。 * path和卸载结束,需要调整节点顺序。 * 创建newIndexToOldIndexMap数组,记录下新节点索引在老节点中的(index+1)。 * 通过getSequence最长递增子序列方法优化diff算法。 14. **processFragment** 处理Fragment 15. processComponent 16. mountComponent 17. setupRenderEffect 18. updateComponent 19. shouldUpdateComponent 20. updateComponentPreRender 21. patchBlockChildren ### 4. schedule.ts ### 5.componentProps.ts 1. initProps 2. updateProps 3. hasPropsChanged ### 6.component.ts 1. createComponentInstance 2. setupComponent + publicInstanceProxy ### 7.apiLifecycle.ts # compiler-core模块(TODO...) ### 1.ast.ts 编译出Node标志位 ### 2.index.ts 1. compile 2. parse 3. createParserContext 4. isEnd 5. parseText 6. getCursor 获取位置信息,根据当前的上下文 7. parseTextData 处理文本内容,并且会更新最新的偏移量信息 8. advanceBy 会进行前进删除 9. advancePositionWithMutation 更新信息 10. getSelection # share模块 存放各种公用的方法 - 类型判断函数 - shapeFlag 二进制类型判断