面试题答案
一键面试Vue 虚拟 DOM 精准识别节点变化并高效复用原理
- 虚拟 DOM 基本概念:Vue 通过创建一个与真实 DOM 结构对应的虚拟 DOM 树,它是一个轻量级的 JavaScript 对象。例如,对于一个
<div>Hello</div>
,虚拟 DOM 可能是{tag: 'div', children: ['Hello']}
。这样在数据变化时,无需直接操作真实 DOM,而是先在虚拟 DOM 上进行计算。 - diff 算法:Vue 利用 diff 算法来比较新旧虚拟 DOM 树,找出变化的部分。
- 同级比较:Vue 的 diff 算法是基于同层级比较的,不会跨层级比较。例如,对于以下结构:
改变为:<div> <p>1</p> <p>2</p> </div>
diff 算法只会比较<div> <p>2</p> <p>1</p> </div>
<div>
下同一层级的<p>
元素。 - key 的作用:当列表元素频繁添加、删除和更新时,给每个列表项设置唯一的
key
至关重要。在 Vue 源码中,当进行列表更新时,会优先根据key
来判断节点是否可复用。例如:
如果没有<ul> <li v - for="(item, index) in list" :key="item.id">{{item.name}}</li> </ul>
key
,Vue 可能会错误地复用节点,而有了key
,Vue 就能精准识别每个节点。在源码中,通过createKeyToOldIdx
等函数建立旧节点的key
到索引的映射,在更新时快速找到可复用的旧节点。 - 四种对比情况:
- 新前与旧前:先比较新旧虚拟 DOM 树开头的节点,如果相同则直接复用,例如新虚拟 DOM 开头是
<p>Hello</p>
,旧虚拟 DOM 开头也是<p>Hello</p>
,则直接复用该节点。 - 新后与旧后:比较新旧虚拟 DOM 树结尾的节点,若相同则复用。
- 新前与旧后:新虚拟 DOM 开头节点与旧虚拟 DOM 结尾节点比较,若相同则移动节点到开头复用。
- 新后与旧前:新虚拟 DOM 结尾节点与旧虚拟 DOM 开头节点比较,若相同则移动节点到结尾复用。
- 新前与旧前:先比较新旧虚拟 DOM 树开头的节点,如果相同则直接复用,例如新虚拟 DOM 开头是
- 遍历剩余节点:经过上述比较后,对于剩余的节点,再进行逐个比较,判断是新增、删除还是更新操作。例如,新虚拟 DOM 有一个节点在旧虚拟 DOM 中找不到,则判定为新增节点。
- 同级比较:Vue 的 diff 算法是基于同层级比较的,不会跨层级比较。例如,对于以下结构:
- 高效复用与 DOM 操作:通过 diff 算法精准找出变化的节点后,Vue 会将变化应用到真实 DOM 上。对于可复用的节点,直接更新其属性,而不是重新创建 DOM 元素。例如,一个
<button>
节点只是文本内容改变,Vue 会直接修改该<button>
的文本,而不是删除旧的<button>
再创建新的。这样大大减少了 DOM 操作,提高了性能,尤其在大型电商应用的复杂动态列表场景下,有效提升了用户体验。