Vue.js 的 Fragment 是虚拟 DOM 的逻辑归组,编译时自动包装多根节点为 Fragment VNode,运行时透传子节点挂载,不生成真实 DOM,用于解耦结构与语义,但不支持绑定属性或事件。

Vue.js 渲染引擎对 Fragment 的支持,核心在于编译层结构改造与运行时 patch 算法的扁平化处理,而非新增一个可挂载的 DOM 节点。它不是组件,也不生成真实元素,而是虚拟 DOM 层的一次“逻辑归组”。
编译阶段:自动包装为 Fragment VNode
当 Vue 3 编译器解析模板时,若发现顶层有多个并列标签(如 <header><main><footer>),不会报错,而是将它们统一构造成一个 type 为 Fragment(Symbol 常量)的 VNode。这个 VNode 的 children 是一个数组,按顺序保存所有子 VNode,自身没有 el、不参与 DOM 创建。
- 无需显式写 <fragment> 标签——Vue 3 SFC 默认启用多根语法,自动包裹
- 手动使用
<Fragment>或import { Fragment } from 'vue'仅用于 render 函数或特殊嵌套场景 - 该 Fragment VNode 在 devtools 中不可见,也不会出现在 DOM 树或组件树中
渲染阶段:子节点透传挂载,跳过 mountElement
渲染器遇到 type === Fragment 的 VNode 时,直接跳过标准的 mountElement 流程,转而遍历其 children 数组,对每个子 VNode 调用 patch(),并将它们全部挂载到同一个父容器(hostParent)中。
- 如果 Fragment 是组件的根 VNode(例如 setup 返回数组),子节点会直接插入组件绑定的宿主元素(如
app.mount('#app')中的 #app) - 不存在“Fragment 挂载”,只有“子节点被父容器承接”——本质是渲染流程的透传优化
- diff 过程中,这些子节点被视为同级兄弟节点,patch 算法按索引逐个比对更新,支持 key 精准复用
设计动机:解耦结构组织与 DOM 实体
Fragment 的存在,是为了让虚拟 DOM 能自然表达“多节点并列”的语义,同时避免强制包裹带来的副作用:
立即学习“前端免费学习笔记(深入)”;
- 在 <table> 内部直接渲染 <tr>,不因包裹 div 破坏 HTML 语义和 CSS 选择器有效性
- 列表项、表单字段组等场景减少无意义的 div 层级,降低内存占用与重排开销
- 渲染函数返回数组(如
return [h('div'), h('span')])与模板多根行为完全一致,统一抽象层
注意边界:它不解决所有“多节点”问题
Fragment 提供的是结构自由,但不改变响应式或生命周期规则:
- 无法给 Fragment 本身绑定 class、style、ref 或事件监听器——它不对应真实节点
- 过渡动画(<transition-group> 除外)不能直接作用于 Fragment,需包裹在有 DOM 的元素上
- 属性继承(如 $attrs)默认透传给第一个子组件,若需分发需显式处理


















