Vue diff算法浅析

一、前言

Vue作为现阶段的主流框架之一,许多项目都使用它来搭建项目前端模块。本文主要介绍Vue中页面渲染时发生的虚拟DOM比对所运用的算法,使大家更加了解Vue。

二、简介

MVVM,即model、view、view-model,业务层、视图层以及两者的绑定层,Vue的设计就是参考了该架构。

<h1>{
   
   {title}}</h1>
​
<script lang='ts' setup>
    const title = 'this is title'
</script>

在Vue中,<h1>标签就是由view层管理,而const title = 'this is title'就是由model层管理的,view-model层要做的就是使这两个数据能保持同步。而要更新标签数据就必不可少的需要重新渲染它。

由于响应式数据改变的渲染是有老vnode存在的,所以Vue就需要最大限度的复用已经创建的DOM元素,而复用的前提就是通过新老vnode进行比对,找出需要更新的内容,最小限度的进行替换。更新过程:

  1. 修改data触发setter,调用Dep.notify通知所有订阅者Watcher;

  2. 重新执行render函数,生成newVnode

  3. 执行patch(vnode,newVnode)diff算法得出最终需要更新的节点;

三、diff算法

1.什么是diff算法

diff算法就是进行虚拟节点比对,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。

换句听得懂的就是

扫描二维码关注公众号,回复: 14923638 查看本文章

diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁

2.步骤

  • 当状态变更时,重新构造一颗由JS对象结构表示的DOM树;

  • 将新的DOM树与旧的DOM树进行比对,记录其差异;(diff)

  • 将记录的差异应用到真实的DOM中;(patch)

3.具体方法

基本策略

  • 同层比较

  • 两边向中间进行比较

举例说明

新旧vnode如下所示:

第一次循环:oldVnode中的startIndex所指向的AendIndex所指向的DnewVnode中的startIndex所指向的D以及newVnode中的endIndex所指向的F分别进行比较(以下比较方式都相同,略过),发现具有相同节点D,直接复用D作为真实节点,oldVnode中的endIndex向前一位,newVnode中的startIndex向后一位。

第二次循环:ACCF比较,得到C相同,复用节点C,指针移动。

第三次循环:ABEF比较,发现没有可复用节点,创建新的节点EnewVnodestartIndex向后移动一位。

第四次循环:ABBF比较,得到B相同,复用节点B,指针移动。

第五次循环:AAF比较,得到A相同,复用节点A,指针移动后发现oldVnode中头指针大于尾指针,则创建newVnode头尾指针间的所有节点(F),跳出循环。

四、小结

  • 当数据发生改变时,订阅者watcher就会调用patch给真实的DOM打补丁

  • 通过isSameVnode进行判断,相同则调用patchVnode方法

  • patchVnode做了以下操作:

    • 找到对应的真实dom,称为el

    • 如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点

    • 如果oldVnode有子节点而VNode没有,则删除el子节点

    • 如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el

    • 如果两者都有子节点,则执行updateChildren函数比较子节点

猜你喜欢

转载自blog.csdn.net/qq_52013792/article/details/127791669