- 作者:老汪软件技巧
- 发表时间:2024-09-23 07:00
- 浏览量:
一:虚拟DOM
虚拟DOM模仿了实际的 DOM 节点,并包含有关节点的信息,例如标签名、属性、子节点等。
简单举个例子:
<li>1li>
<li>2li>
<li>3li>
Obj = { // 虚拟dom结构, 根据虚拟dom生成真实dom
tag: 'ul',
children: [
{tag: 'li', children: [{vnode: {text: '1'}}]},
{tag: 'li', children: [{vnode: {text: '2'}}]},
]
}
在运行时,会把代码编译成一个对象,也就是虚拟 DOM,然后生成真实的 DOM,但在实际中,Vue 使用了一种更加复杂的对象结构来存储虚拟节点(VNode),并且包含了更多的元信息,比如节点的类型、属性、事件监听器等等。
二:diff算法
在DOM结构发生改变时,会生成一个新的虚拟DOM,此时就需要一个算法来比较新旧DOM的不同来更快速的渲染,也就是diff算法。
比较过程中,会根据虚拟DOM树的结构,一层一层比较,首先比较的是两个虚拟 DOM的根节点是否相同,如果根节点相同才会继续检查子节点,看是否有可复用的DOM,否则不会再继续比较子节点。
那么会有一个疑问了,如果两个虚拟DOM只有根节点不同,子节点完全一样呢?确实,这样的两个新旧虚拟DOM树可复用高,但是如果 diff算法改成了不依据根节点是否相同来确定是否要检查子节点,那么会对逐一对比子节点找可复用部分,加大了引擎压力,有点捡了芝麻丢了西瓜那味了
2.1.判断两个跟节点是不是相同判断两个节点上的key是否相同判断两个节点的标签名是否相同标签上的属性2.2.diff比较过程旧首节点,新首节点,旧尾结点,新尾结点不是相同的节点,直接销毁 oldVnode,启用 newVnodenewVnode是不是文字节点 (直接让浏览器修改文字)有新的children 没有旧children (记录新增)没有新的children 有旧children (记录删除)有新的children 有旧children (diff 核心工作 两两节点比较)三:diff中的key3.1.key为什么不能是index?
diff 中判断两个节点是否相同首先判断的就是两个节点的key是否相同, 如果用index作为key,index不会随着元素位置的变更而移动,从而导致相同可复用的节点被认为不相同,降低了DOM的复用性,浪费性能
3.2.可不可以用随机数做key?
当然不可以,和index的原因是一样的,但比index效率更低下。用随机数的话新旧树的每一个DOM结构都是不同的key,用index,还可能有些DOM结构在新树中index没变,然后得以复用。
四:虚拟DOM的好处
想必友友们在其他文章中已经看过无数遍这个问题的答案了-->因为虚拟DOM性能好。
其实不然,虚拟DOM实际就是把HTML读成JS对象,再生成HTML结构,用虚拟DOM性能并不会有所提高,会开销很多v8的性能。一个新的前端框架svelte就是主打的无虚拟DOM,此外连尤雨溪自己都说在VUE4会把虚拟DOM砍掉。
优点:
跨平台:支持构建可以在多个平台上运行的应用程序,虚拟 DOM 允许开发者使用一套统一的 API(JavaScript)去描述用户界面,而不需要关心底层的具体实现细节,这在一定程度上促进了跨平台开发。分摊了浏览器渲染线程的压力,减少了回流重绘:当数据发生变化时,diff 算法能够计算出最小化的 DOM 更新操作,这样只需要对实际发生变化的部分进行更新。避免了不必要的 DOM 操作,从而减少了浏览器的回流和重绘,提高页面的响应速度和流畅度。