# Vue2源码练习 **Repository Path**: cede-lf/vue2-source-code-exercise ## Basic Information - **Project Name**: Vue2源码练习 - **Description**: vue、vuex、vue-router源码 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-01-03 - **Last Updated**: 2024-01-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: Vue源码 ## README # 一、项目初始化 1.初始化 npm 生成 package.json rollup 2.配置相关文件 3.rollup --> rollup.configjs 4.package.json 支持新版本 rollup 设置 type='moudle' 支持 Es6 语法 # 二、创建 Vue 初始化 ## 数据劫持 - index.html 创建对象 在 vue 实列 vm 上挂载对象 ### 初始化 data - 分为两种情况劫持: #### 对象 - 通过 Object.defineProperty - 缺点:只能对对象里的一个属性劫持 所以要使用递归 - 小 Tip:数据更改后重新劫持、当 data 中式函数的时候该更改 this 指向 data.call(this) # 三、数据更新 Vue 初次渲染=》先初始化数据=》模板编译=》变成 render()=》生成虚拟 dom 节点=》变成真实 dom=》放到页面 模板编译 : template render 注意 el 挂载的地方 render()->template 生命周期的实现 - 1.Vue.mixin({}) 混入 - 2.设计模式 订阅发布 vue options:{data:[],watch:[]} - 3.vue 中组件更新的策略:以组件为单位 每添加一个组件 就给每一个组件添加一个 wathcher,属性变化后更新 watcher - 4.收集依赖 vue dep 按照 data 的属性来有多少属性就有多少 dep 依赖是一一对应的,watcher:在视图上用几个就有 wather 对应组件里面的每个属性 data 与 dep 一对一 dep.msg=[w1,w2]; dep 和 watcher 多对多 计算属性 互相存储 watcher 里存放 dep 双向记忆 走的流程 更新 render 获取 实列上 data 里面的属性值触发代理的 get 方法生成 dep 实列, 拿到一开始 render(页面)前生成的唯一一个的 wacher 去把本次生成的带有 id 标识的 dep 存储到数组,然后本次生成的 dep 将 wather 也存储下来 形成了 wather 有 dep dep 又有 wather 套娃组合,记住的是当 render 函数生成 dep 的时候因为 watcher 只有一个(初始化页面生成的) 所以每次生成 dep 的时候都会调用同一个 watcher 去加入本次生成的 dep 所以是一对多的关系, ## 思路 #### 1:我们要给所有对象类型增加一个 dep[] #### 2:获取数组的值,会调用 get 方法我们希望让当前数组这个渲染的 wanter ##### 2.1 需要获取到当前 dep ##### 2.2 当前面对数组取值的时候,我们就让数组的 dep 记住这个 watcher #### 3 我们更新数组的时候调用 push,等等方法,找到我们这个 watcher 进行跟新 ## 实现对对象的收集依赖 给每个属性生成 dep ### nextTick()实现 所有的组件触发更新的方法都加入任务队列统一处理 然后做一次更新,把 vue 更新的方法和用户写的方法再加入任务队列等待异步执行,等同步都执行完成后在执行异步方法, 执行 vue 更新和用户传来的队列函数。总体就是相同 id 的同步的进程执行多次要等异步的执行完成后才能执行,不同 id 的加入任务队列等待异步执行。 ### wath 的实现 因为 wath 创建的 watcher 加入 dep 后,数组和非数组都用了代理所以返回的值作为旧值 因为数组的方法劫持用了修改的时候用的原生的 push。。方法所以开始 赋值的旧值也会改变导致获取不到旧值 非数组得到的是固定对象 内存地址不同 # diff 算法 · 1vue 操作 vnode {tag: 'div' data: children} · 2 真正 DOM · for(let key in app){ console.log(key) } /\*\* - odls olde - old b a c - / \ - / \ - / \ - new c a b d - onews newe - dom b a c - ① 依次比较,当比较成功后退出当前比较 ② 渲染结果以 newVnode 为准 ③ 每次比较成功后 start 点和 end 点向中间靠拢 ④ 当新旧节点中有一个 start 点跑到 end 点右侧时终止比较 ⑤ 如果都匹配不到,则旧虚拟 DOM key 值去比对新虚拟 DOM 的 key 值,如果 key 相同则复用,并移动到新虚拟 DOM 的位置 ## 为什么添加 key 不用索引? - 因为 key 遍历的时候是可以跟着子集走的,索引不是是跟着标签走的,所以当 diff 比较的时候找到相同的老旧索引但是里面子集不一样就会被重新创建 - 如果用的是 key 那 diff 比较的时候就会找到两个相同的 key 里面的子集也是一样的只是位置不一样,更新位置就好了,这种情况所以还是 key 好。 ## 更新数据 最小量更新进行比对 old new 用虚拟 dom 比对 - 创建两个虚拟的 dom - 比对 拿到老的节点和新的节点做对比 不同的地方进行更新 # computed 的使用 将实例化的 computed 代理到实列上并判别是对象还是方法 实现缓存:通过高阶函数(参数是一个函数或者返回值是一个函数) 1 : computed 使用 2:初始化 computedT:实现 object.defineProperty 代理 3:具有缓存机制通过一个变量 dirty watcher 实现的方式:通过高阶函数:高阶函数就他的参数是一个函数或者返回值是一个函数 4:面试题 watch 和 computed computed 具有缓存机制通过一个变量 dirtywatch 问题:再视图中更新数据 fullName 没有效果 /以为这里有多个 watcher 渲染 watchercomputed watcher