fragment 是 vue 3 中不挂载、无 dom 的编译时逻辑包装器,用于多根节点结构组织,其子节点由父容器直接透传挂载。

Vue 中的 Fragment 并不真正“挂载”——它本身没有 DOM 元素,不参与真实节点创建和插入,而是一个编译时的逻辑包装器,用于包裹多个同级子节点,在 VNode 层保持结构完整性,最终由父组件或渲染函数“透传”给宿主元素。
Fragment 是什么:不是组件,也不是真实 DOM 节点
从 Vue 3 开始,单文件组件(SFC)支持多根节点(即不需要强制包裹一层 div),编译器会自动将模板顶层多个并列标签包装成一个 Fragment 类型的 VNode。这个 VNode 的 type 是 Fragment(一个 Symbol 常量),children 是一个数组,包含所有顶层子 VNode。
它没有对应的 DOM 元素,所以不会调用 hostInsert、不生成 el,也不进入标准的 mount 流程(如 mountElement)。它的作用纯粹是组织 vnode 树结构,让多个子节点能被统一处理。
Fragment 如何“生效”:靠父级容器承接子节点
Fragment 的渲染行为完全依赖于其父级。当渲染器遇到 type 为 Fragment 的 VNode 时,会直接遍历它的 children,逐个执行 patch() —— 也就是把每个子 VNode 挂载到同一个父容器中(比如父组件的 hostParent 或当前组件的根 DOM 容器)。
这意味着:
- Fragment 自身不创建任何 DOM 节点,也不会出现在 devtools 的组件树中作为独立节点
- 它的子节点会“扁平化”插入到父容器中,顺序与
children数组一致 - 如果 Fragment 是根 VNode(如 setup 返回多个节点的 render 函数),则这些子节点直接挂载到组件绑定的宿主元素(如
app.mount('#app')中的 #app 元素)
在 render 函数中显式使用 Fragment
你可以手动导入并使用 Fragment,例如:
vimport { h, Fragment } from 'vue'
export default {
render() {
return h(Fragment, [
h('div', '第一项'),
h('span', '第二项'),
h('p', '第三项')
])
}
}
此时返回的 VNode type 就是 Fragment,效果等同于 SFC 多根模板。注意:不能给 Fragment 设置 class、ref、v-show 等 prop(会被忽略),因为它不对应真实元素。
注意事项与常见误区
Fragment 不是万能的“透明容器”:
-
不能绑定 ref:Fragment 上的
ref不会生效,需放在具体子元素上 - 不能用 v-if/v-for:这些指令必须作用于可挂载的节点(如 element 或 component),不能直接写在 Fragment 标签上(SFC 中也不允许)
-
过渡动画受限:
<transition-group></transition-group>可以包裹 Fragment 子节点,但<transition></transition>不能包裹 Fragment(因为无 DOM 节点,无法触发 enter/leave 钩子) - 服务端渲染(SSR)中无副作用:Fragment 同样不产生 HTML 字符串,子节点内容直接拼接进输出流
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










