虚拟DOM
- 用JS对象描述DOM的层次结构
- DOM转换虚拟DOM,属于模板编译原理
编译原理
- JS编译原理:编译(词法分析、语法分析、代码生成)、JS引擎执行
- 模板编译(模板 - 模板编译 - 渲染函数):
a、解析器:将模板解析成AST
b、优化器: 遍历AST,检测出所以静态子树
c、代码生成器:将AST转换成渲染函数
snabbdom 库
- 主程序由ts编写,可打包build成js,*.d.ts属于编译打包后的预留文件
- DOM库
- 运行时,必须安装webpack5.0
源码分析
h函数(作用: 用来产出生虚拟节点)(虚拟节点需要函数patch,渲染到真实DOM显示)
调用: h('div', 'hello')
结果:(elm为空,说明没有渲染到页面DOM上)
{
children:..
data:...
elm:...
sle:...
}
patch函数
特点
1.最小量更新
例如:
<ul>
<li> A</li>
<li> B</li>
</ul>
更新为
<ul>
<li> A</li>
<li> B</li>
<li> C</li>
</ul>
此时元素A、B不更新,只更新C。
key的重要性: key是节点唯一标识。告诉diff算法,元素是更新前后同一个节点.
例如:
<ul>
<li> A</li>
<li> B</li>
</ul>
更新为
<ul>
<li> C</li>
<li> A</li>
<li> B</li>
</ul>
此时元素A、B更新了,如果加key则不更新。
2. 同一个虚拟节点,才进行最小量更新,否则暴力删除旧的,添加新的虚拟节点
例如:
<ul>
<li> A</li>
<li> B</li>
</ul>
更新为
<ol>
<li> A</li>
<li> B</li>
</ol>
此时,ul与ol不一样所以旧的ul节点将会直接删除
3.虚拟节点只会同层比较,否则暴力删除旧的,添加新的虚拟节点
例如:
<div>
<ul>
<li> A</li>
<li> B</li>
</ul>
</div>
更新为
<div>
<div>
<ul>
<li> A</li>
<li> B</li>
</ul>
</div>
</div>
此时,新的节点div与旧的ul节点同层,但内容不一致,因此旧的ul直接删除
流程
- 第一步: 判断oldVnode是虚拟节点还是DOM节点,如果不是将oldVnode转换成虚拟节点。
- 第二步: 判断oldVnode和newVnode是不是同一个节点,如果不是,将暴力删除旧的,插入新的。否则进行最小量更新精细化比较。
判断是否同一个虚拟节点原理(旧节点的key要和新节点的key相同且旧节点的选择器要和新节点的选择器相同)
精细化比较算法
1、判断newVnode与oldVnode是否同一个对象
2、判断newVnode是否有text属性
3、判断oldVnode是否有children属性
比较大概思想
两个虚拟DOM遍历,四个索引命中查找,命中其中一个,就不再进行命中判断、继续下一个判断流程;如果没有命中,就需要循环查找新虚拟node在旧虚拟node是否存在。
1、新虚拟Node前序索引与旧虚拟node前序索引比较
2、新虚拟Node倒序索引与旧虚拟node前序索引比较(这种情况命中,新虚拟Node指向Node移动到旧的node之后)
3、新虚拟Node倒序索引与旧虚拟node倒序索引比较(这种情况命中,新虚拟Node指向Node移动到旧的node之前)