document.createDocumentFragment() 是唯一安全创建 DocumentFragment 的方式;它返回 nodeType 为 11、parentNode 恒为 null 的纯片段对象,不可复用、无 innerHTML、不支持 querySelector,插入后自动清空。

document.createDocumentFragment() 是唯一安全创建方式
别用 new DocumentFragment(),它不合法;也别手动模拟一个空节点去替代——行为不一致,且在旧版 Safari 或 IE 中可能直接报错。所有现代浏览器都支持 document.createDocumentFragment(),返回值一定是 nodeType === 11 的纯片段对象,parentNode 恒为 null。
常见错误现象:代码里写了 const frag = new DocumentFragment(),控制台没报错但后续 frag.appendChild() 失效,或插入后节点消失——本质是创建了无效对象,浏览器静默忽略后续操作。
- 必须每次批量操作前调用一次
document.createDocumentFragment(),不能复用已插入过的 fragment(插入后自动清空) - 不要缓存 fragment 实例用于多次插入,重复使用会得到空内容
- 若需结构复用,应封装成函数,每次调用都新建 fragment
往 DocumentFragment 塞节点时 parentNode 会立即变更
把一个已挂载的 li 直接 frag.appendChild(li),这个 li 会从原位置被移走,不是复制。如果你循环中先 append 进 fragment,再想给同一个 li 加 class 或绑定事件,会发现它已经脱离原始上下文,li.parentNode 变成了 fragment,不再是页面中的容器。
适用场景:动态生成列表、表格行、卡片组等需要保留节点引用或后续交互的批量插入。
立即学习“前端免费学习笔记(深入)”;
- 如需保留原节点并同时插入副本,用
li.cloneNode(true)再 append - 如需统一设置属性或事件,务必在
frag.appendChild()之前完成,比如li.dataset.id = i、li.addEventListener('click', handler) - 避免在 fragment 填充过程中读取真实 DOM 的
offsetHeight或getBoundingClientRect(),这会强制触发同步重排,抵消 fragment 优化效果
fragment.innerHTML = '...' 会静默失败
DocumentFragment 没有 innerHTML 属性,写 frag.innerHTML = '<li>test</li>' 不会报错,但也不起作用——赋值被忽略,fragment 保持为空。这是最容易踩的坑之一,尤其从 div.innerHTML 习惯迁移到 fragment 时。
正确做法是把 HTML 字符串转成真实节点再进 fragment:
- 推荐用
template标签:const t = document.createElement('template'); t.innerHTML = htmlString; frag.append(...t.content.children); - 或用
DOMParser:const doc = new DOMParser().parseFromString(htmlString, 'text/html'); frag.append(...doc.body.children); - 纯静态内容且无 XSS 风险时,可改用
insertAdjacentHTML('beforeend', htmlString),但它不经过 fragment,也不支持节点复用
插入后 fragment 自动清空,且不支持 querySelector
执行 container.appendChild(frag) 后,frag.childNodes.length 立刻变成 0,不能再拿来二次插入。另外,frag.querySelector('li') 总是返回 null,因为 fragment 不参与 CSS 选择器匹配,也没有 ownerDocument 关联样式表。
调试时想确认 fragment 内容是否正确,临时方案是:
- 先
document.body.appendChild(frag)看一眼,再用document.body.removeChild(frag)移走 - 用
console.log(frag.children)或Array.from(frag.childNodes)查看子节点列表 - 对 table 插入要特别小心:不能直接把
tr塞进 fragment 再 append 到table,得先 append 到tbody或thead,否则浏览器会静默修正结构,导致预期外的 DOM 重组
height、float、display: grid)。如果只是往一个 display: none 的父元素里塞 fragment,重排本就不会发生,用不用 fragment 差异不大。



















