Vue3比较元素-详细步骤

239 阅读2分钟

接上回,如果存在老的虚拟节点,我们就走更新流程

更新的逻辑思考

  • 如果前后完全没关系,删除老的,添加新的
  • 老的和新的一样,复用。属性可能不一样,再比属性,更新逻辑
  • 比儿子

判断老的虚拟节点和新的虚拟节点是不是同一个

image.png

如果老的虚拟节点存在并且老的虚拟节点和新的虚拟节点不是同一个

image.png

  • 删除老的
  • 把老的置为null,然后就会走初始化挂载流程了

文本更新

image.png

  • 如果新虚拟节点的类型是文本,并且老的虚拟节点不为null,说明老的虚拟节点和新生成的虚拟节点是同一个东西。我们可以直接复用老的真实元素
  • 如果老的虚拟节点的儿子节点不等于新的虚拟节点的儿子节点,我们直接设置这个元素里的内容为最新的

元素更新

image.png

  • 如果新的虚拟节点的类型是元素节点,并且老的虚拟节点不为null,说明说明老的虚拟节点和新生成的虚拟节点是同一个东西,都是元素节点,那我们就进行元素的比对

patchElement核心方法

image.png

  • 先复用节点,再比较属性,最后比较儿子
  • 拿到新老的的属性props,我们写个方法patchProps进行比较
  • 遍历新的属性,把老的属性覆盖掉
  • 再次循环老的属性,查找老的有,新的没有的情况,则是删除

比完属性之后,开始比较儿子,调用patchChildren方法处理

image.png

子元素比较情况

image.png

  • 拿到老虚拟节点的儿子和新虚拟节点的儿子
  • children有可能是文本、数组或者是空null三种情况
  • 最核心的是新的是数组,老的也是数组的情况,需要进行diff算法比较

patchChildren方法

image.png

  • 取老的虚拟节点的shapeFlag和新的虚拟节点的shapFlag来对新旧虚拟几点儿子的类型进行判断
  • 如果新的是文本,老的是数组,就删除老的所有子节点,然后把新的文本设置进去
  • 如果新的是文本,老的也是文本,就直接更新文本即可

image.png

image.png

  • 上述已解决新的为文本的三种情况

如果新虚拟节点的儿子为数组或者为空

image.png

  • 如果新虚拟节点的儿子是数组,老的虚拟节点的儿子也是数组,则进行diff算法比较
  • 如果现在不是数组,之前是数组则删除之前的所有子节点

我们还剩下现在是空,之前是数组或者文本的情况

image.png

至此,除了diff的情况,之外的情况我们已全部处理,下一篇,我们将实现Vue3的diff算法