面试题答案
一键面试Vue Fragment 渲染时虚拟 DOM 的生成与对比过程
- 虚拟 DOM 生成:
- 在 Vue 组件渲染过程中,当遇到 Fragment(在 Vue 3 中,Fragment 是一种无需额外 DOM 节点包裹的组件结构,用
<>...</>
语法表示)。Vue 会根据组件模板的结构,将 Fragment 内的子节点构建为虚拟 DOM 树。例如,模板<><div>content1</div><span>content2</span></>
,Vue 会创建一个虚拟 DOM 树,根节点是 Fragment 对应的虚拟节点,其 children 数组包含<div>
和<span>
对应的虚拟节点。 - 每个虚拟节点包含标签名(如
div
、span
)、属性、子节点列表等信息,以描述真实 DOM 元素的结构和数据。
- 在 Vue 组件渲染过程中,当遇到 Fragment(在 Vue 3 中,Fragment 是一种无需额外 DOM 节点包裹的组件结构,用
- 虚拟 DOM 对比:
- 当数据发生变化,Vue 会重新渲染组件,生成新的虚拟 DOM 树。然后将新的虚拟 DOM 树与旧的虚拟 DOM 树进行对比(称为
patch
过程)。 - 对比从根节点开始,对于 Fragment 对应的根虚拟节点,会依次对比其 children 数组中的子节点。如果子节点的标签名、属性等发生变化,会记录这些变化,并根据变化生成对应的 DOM 操作指令。例如,如果
<div>
标签的class
属性发生变化,就会生成更新class
的指令。如果某个子节点被删除或新增,也会记录相应的插入或删除指令。最后,根据这些指令批量更新真实 DOM,以高效地反映数据变化。
- 当数据发生变化,Vue 会重新渲染组件,生成新的虚拟 DOM 树。然后将新的虚拟 DOM 树与旧的虚拟 DOM 树进行对比(称为
优化虚拟 DOM 对比性能的策略
- 减少不必要的渲染:
- 原理:通过
shouldComponentUpdate
(Vue 2 中)或watchEffect
(Vue 3 中结合shallowRef
等)等机制,控制组件何时进行重新渲染。在 Vue 2 中,shouldComponentUpdate
方法返回false
时,组件不会重新渲染,也就不会进行虚拟 DOM 的生成和对比。在 Vue 3 中,shallowRef
只对浅层数据进行响应式追踪,当数据变化只影响浅层数据且组件依赖浅层数据时,使用shallowRef
可以减少不必要的重新渲染。 - 适用场景:适用于组件状态变化频繁,但实际对 DOM 有影响的变化较少的场景。例如,一个显示用户信息的组件,用户信息中的一些无关紧要的字段(如用户的注册 IP 地址,仅用于记录,不展示在 DOM 中)发生变化时,通过控制不重新渲染组件,可避免不必要的虚拟 DOM 生成和对比。
- 原理:通过
- 使用 key:
- 原理:在列表渲染中,为每个列表项添加唯一的
key
。当数据变化时,Vue 基于key
来更准确地识别新旧虚拟 DOM 中的节点关系。如果没有key
,Vue 可能会采用更保守的策略,如重新排序所有节点。而有了key
,Vue 可以更精准地判断哪些节点需要移动、更新或删除,从而减少不必要的 DOM 操作。 - 适用场景:在任何列表渲染的场景都适用,比如展示商品列表、用户列表等。通过为每个列表项提供唯一
key
,可以显著提高虚拟 DOM 对比和更新的效率。
- 原理:在列表渲染中,为每个列表项添加唯一的
- 局部更新:
- 原理:将大组件拆分成小组件,使得数据变化时只影响局部组件的虚拟 DOM 生成和对比。例如,一个复杂的页面可以拆分成多个功能模块组件,当某个模块的数据发生变化时,只重新渲染该模块对应的组件,而不会影响其他模块的虚拟 DOM,减少整体的对比范围。
- 适用场景:适用于页面结构复杂、包含多个相对独立功能区域的应用。如电商平台的商品详情页,将商品图片展示、商品描述、评论区等拆分成不同组件,当评论数据更新时,只更新评论区组件的虚拟 DOM,提高性能。