DocumentFragment 是不属 DOM 树的轻量级文档对象,操作它不会触发重排重绘;需用 document.createDocumentFragment() 创建,通过 createElement + appendChild 或临时 div 解析 HTML 字符串后移入,再用 appendChild/insertBefore 一次性插入真实 DOM。

DocumentFragment 是什么,为什么它能避免重排重绘
DocumentFragment 是一个轻量级的文档对象,它不直接属于 DOM 树,因此对它的操作(如 appendChild、insertBefore)不会触发浏览器的布局计算或样式重排。当你在循环中反复 appendChild 到真实 DOM 节点时,每次都会可能触发重排;而先批量操作 DocumentFragment,再一次性插入,就把多次重排压缩成一次。
关键点在于:它不是“虚拟 DOM”,也不需要框架支持,是原生 API,所有现代浏览器都支持。
如何正确创建并填充 DocumentFragment
不要用 document.createDocumentFragment() 后再手动 cloneNode 或 innerHTML 赋值——DocumentFragment 不支持 innerHTML,设了也没用;也不能直接用 new DocumentFragment()(会报错)。
推荐做法是:
- 用
document.createDocumentFragment()创建空片段 - 用
document.createElement()创建每个子节点,再fragment.appendChild(element)追加 - 如果已有 HTML 字符串,需先用临时
div解析,再把子节点移入 fragment(不能用innerHTML直接写到 fragment)
示例(安全解析字符串):
const html = '<li>A</li><li>B</li>';
const temp = document.createElement('div');
temp.innerHTML = html;
const fragment = document.createDocumentFragment();
while (temp.firstChild) {
fragment.appendChild(temp.firstChild);
}
插入时必须用 appendChild 或 insertBefore,不能用 innerHTML
常见错误是把 fragment 当作字符串拼接容器,然后试图 parent.innerHTML += fragment——这完全失效,因为 fragment.toString() 返回 [object DocumentFragment],不是 HTML 文本。
正确插入方式只有两种:
-
parent.appendChild(fragment)(最常用) -
parent.insertBefore(fragment, refNode)(指定位置插入)
注意:fragment 插入后自动清空,再次使用需重新创建;它不保留对原始节点的引用,插入即“转移”节点所有权。
和 innerHTML 对比:何时该选 DocumentFragment
如果你只是静态插入已知结构的 HTML 字符串,innerHTML 更快、更简洁;但只要涉及动态创建、需绑定事件、要复用节点、或需精确控制元素实例(比如给每个 li 设置不同 dataset),DocumentFragment 就不可替代。
性能差异在几百个节点以上才明显;少于 20 个节点时,两者的差距几乎感知不到,别过早优化。
容易被忽略的一点:fragment 本身不触发事件冒泡,也不参与 CSS 选择器匹配——它只是中转站,所有样式和事件必须在插入 DOM 后才生效。


















