vue3源码解读--diff

目录

    vue2源码

    vue3源码

前言

    diff作为前端为数不多的算法实例,一直以来都被津津乐道。之前了解过vue2的实现过程:它采用双端比较,先从前往后比较,复用同类型节点,遇到不同类型时停止,从后先向前比对,最后再交叉对比

    但是之前参读的并不够深入,比如对其如何算出哪些节点是要移除的,哪些是要移动的等

    今天带着查漏补缺的目的来学习下vue3,看其是否对diff有所优化并彻底搞懂之前遗留下来的懵懂

源码定位

    由于diff算法发生在动态列表下的patch更新阶段,故将代码定位到patchChildren位置

示例1:前后列表完全一致

    从前向后比较,遍历到每一个li时,对li复用,对li的子节点做比对更新,由于前后列表的key和元素类型完全一致,故遍历结束后即完成

示例2:长列表更新为短列表

    和上一个示例一样,对于前四个元素而言,其元素类型和key完全一致,故均被复用,当while结束后,e1还剩一个未遍历到,此时i>e2,需要将旧列表的最后一个元素卸载掉

示例3:短列表更新为长列表

    同样的,前四个元素将被复用,while结束后,e2还剩一个元素未被遍历到,此时i>e1<=e2,需要将新列表的最后一个元素创建并加入

示例4:前后列表存在位置变更

    根据示例一,我们知道由于key值的变化,第一个即被视为非同一节点,故直接跳出,进入循环二:从后向前比对,其核心逻辑和循环一一致:找到同类型元素进行复用

    当循环二结束,旧列表的最后一个li被保留,此时e1=e2=2,i=0。根据示例二和示例三,我们知道当存在新增或删除元素时,i的值要大于e1或者e2

    故进入else逻辑

    经过前两个while循环,首尾同类型元素已经被保留,故需要将中间未被处理的部分拿出来,这里通过遍历将这些节点的唯一key值及其在新列表中的位置缓存一份

    对旧列表中未被处理部分进行遍历,拿到每一个key值到keyMap中查找,如果没有查找到,则说明新列表中需要删除掉,否则则说明是可复用元素,则对其子节点进行比对更新,那么能否说明存在位置移动呢?

    首先,如果不存在位置移动,则在key值和元素类型相同的情况下,必然在前两轮while循环中被处理

    则必定是元素类型或key值发生了变化

    由于patch本身还会再次比对元素类型,故这里只需要根据key来做元素位置变化的判断依据即可

    则

    如果一个元素的位置发生了变化(非平移,应是交换),则一定存在一个元素移动后的位置更小

    故

    需要记录下元素移动的最远位置:即框红位置

    最后,处理位置交换和新元素创建

你可能感兴趣的:(vue3源码解读--diff)