虚拟DOM与diff算法

95 阅读2分钟

什么是虚拟DOM?

虚拟DOM把真实DOM变成了一个js对象。虚拟DOM用js对象描述DOM的层次结构,DOM中的一切属性都在虚拟DOM中有对应属性。

为何需要虚拟DOM?

因为diff是发生在虚拟DOM上的,新虚拟DOM和老虚拟DOM进行diff(精细化比较),算出应该如何最小量更新,最后反映到真正的DOM上。

什么是snabbdom?

snabbdom 库 是著名的虚拟DOM 库,是diff 算法的鼻祖,Vue源码借鉴了snabbdom 。DOM库不能在nodejs环境运行,所以需要搭建webpack和webpack-dev-server开发环境,不需要安装任何loader

注:webpack4没有读取身份证中exports的能力,webpack5才开始支持这个能力

虚拟DOM如何被渲染函数(h函数)产生?

h函数是用来参生虚拟节点的。h函数可以嵌套使用,从而得到虚拟DOM树

Snipaste_2022-10-16_10-48-59.jpg

h函数其实主要执行了vnode函数。根据传入h函数的参数来决定执行vnode函数时传入的参数。而vnode函数功能就是把传入的5个参数组成合成对象,即虚拟DOM。然后h函数再把这个虚拟DOM返回。

一个虚拟节点都有哪些属性?

{

    children: undefined,    // 子元素

    data: {},   // 节点的属性、样式

    elm: undefined, // 对应真正DOM节点,如果为undefined,表示该节点还未上树

    key: undefined, // 节点唯一标识

    sel: "div", // 选择器

    text: "我是一个盒子"  // 文字

}

diff算法

  • diff算法:最小量更新。不会让一样的重新变,而是只变要变的。(一定要加key才能这样!)
  • key是节点的唯一标识,服务于最小量更新。
  • 只有是同一个虚拟节点(同一虚拟节点即选择器和key都相同),才能进行精细化比较,否则就是暴力删除旧的、插入新的。
  • 只进行同层比较,不会进行跨层比较。即使是同一片虚拟节点,但是跨层了就会暴力删除旧的、然后插入新的。

diff算法比对

Patch函数

比较的第一步

Snipaste_2022-10-16_18-10-51.jpg

patchVnode函数

对比同一个虚拟节点

diff算法的四种命中查找:

新前与旧前

新后与旧后

新后与旧前(此种发生了,涉及移动节点,那么新前指向的节点,移动的旧后之后)

新前与旧后(此种发生了,涉及移动节点,那么新前指向的节点,移动的旧后之前)

Snipaste_2022-10-20_21-20-16.jpg

命中一种就不在进行命中判断,如果都没命中就开始循环查找了

新增的情况:

Snipaste_2022-10-18_20-56-55.jpg

删除的情况:

如果新节点先循环完毕老节点还有剩余节点,那它们就是要被删除的节点

Snipaste_2022-10-18_23-54-29.jpg

复杂的情况:

Snipaste_2022-10-20_20-59-16.jpg

Snipaste_2022-10-20_21-11-22.jpg