面试题答案
一键面试虚拟 DOM 工作机制
- 创建:
- 当 Vue 组件初始化时,会根据组件的模板和数据状态生成虚拟 DOM。Vue 通过编译模板,将其转换为渲染函数。渲染函数执行时会创建虚拟 DOM 树。每个节点都是一个 JavaScript 对象,包含标签名、属性、子节点等信息。例如,对于模板
<div id="app">Hello, {{name}}</div>
,会生成一个描述该div
及其子文本节点的虚拟 DOM 对象。 - 虚拟 DOM 树的根节点对应组件的根元素。
- 当 Vue 组件初始化时,会根据组件的模板和数据状态生成虚拟 DOM。Vue 通过编译模板,将其转换为渲染函数。渲染函数执行时会创建虚拟 DOM 树。每个节点都是一个 JavaScript 对象,包含标签名、属性、子节点等信息。例如,对于模板
- 更新:
- 当组件的数据发生变化时,Vue 会重新执行渲染函数生成新的虚拟 DOM 树。然后通过对比算法(如
diff
算法)将新的虚拟 DOM 与旧的虚拟 DOM 进行比较。 diff
算法首先比较两棵树的根节点,如果根节点的标签或 key 发生变化,则直接替换整个子树。如果根节点标签相同,则继续比较子节点。对于子节点,diff
算法会按顺序依次比较,找出有变化的节点。例如,如果一个列表中的某一项数据改变,diff
算法会定位到对应的虚拟 DOM 节点。- 找到变化后,Vue 会将变化应用到实际的 DOM 上,只更新那些真正有变化的部分,而不是重新渲染整个组件对应的 DOM。
- 当组件的数据发生变化时,Vue 会重新执行渲染函数生成新的虚拟 DOM 树。然后通过对比算法(如
- 删除:
- 当某个节点在新的虚拟 DOM 树中不存在时,对应的真实 DOM 节点会被删除。例如,从列表中移除一项数据,新的虚拟 DOM 树中该项对应的节点就不存在了,Vue 会找到并删除真实 DOM 中的对应节点。
Fragment 功能与虚拟 DOM 的配合及对渲染性能的提升
- Fragment 概念:Fragment 即片段,在 Vue 3 中,Fragment 允许组件返回多个根节点,而无需像 Vue 2 那样必须有一个单一根节点包裹。例如,组件可以返回
<template><div>First</div><span>Second</span></template>
,这里div
和span
就是 Fragment 的子节点。 - 配合方式:
- 创建时:在创建虚拟 DOM 时,Fragment 会作为一个特殊的节点存在于虚拟 DOM 树结构中。它本身没有真实的 DOM 标签对应,主要用于包裹多个子节点。例如上述例子中,虚拟 DOM 树会有一个 Fragment 节点,其包含
div
和span
两个子节点对象。 - 更新时:当数据变化导致虚拟 DOM 更新,
diff
算法同样会作用于包含 Fragment 的虚拟 DOM 树。由于 Fragment 没有真实 DOM 标签,在对比时主要关注其内部子节点的变化。例如,如果div
中的文本发生变化,diff
算法会定位到div
对应的虚拟 DOM 子节点,然后更新真实 DOM 中的div
节点,而不会影响到span
节点,这与普通虚拟 DOM 更新机制类似,但因为没有多余的单一根节点包裹,减少了不必要的 DOM 操作。 - 删除时:如果某个子节点从 Fragment 中移除,Fragment 对应的虚拟 DOM 会更新,移除该子节点。真实 DOM 中对应的节点也会被删除,并且由于没有多余的包裹节点,删除操作相对更直接,不会产生对包裹节点的无效操作。
- 创建时:在创建虚拟 DOM 时,Fragment 会作为一个特殊的节点存在于虚拟 DOM 树结构中。它本身没有真实的 DOM 标签对应,主要用于包裹多个子节点。例如上述例子中,虚拟 DOM 树会有一个 Fragment 节点,其包含
- 性能提升:
- 减少 DOM 节点数量:在 Vue 2 中,为了符合单一根节点的要求,可能会添加一些不必要的包裹节点。而 Vue 3 的 Fragment 避免了这种情况,减少了 DOM 树的层级和节点数量,降低了渲染的复杂度。例如在复杂列表渲染中,如果每个列表项都不需要额外的包裹节点,使用 Fragment 可以减少大量冗余节点,提升渲染性能。
- 精准更新:由于 Fragment 直接包裹子节点,
diff
算法能更精准地定位和更新变化的节点,减少无效的 DOM 操作。例如在一个包含多个独立小组件的组件中,每个小组件作为 Fragment 的子节点,当其中一个小组件数据变化时,diff
算法可以快速定位到该小组件对应的虚拟 DOM 子节点,只更新该部分真实 DOM,而不会影响其他小组件,从而提升了整体的渲染性能。