template.content 返回 documentfragment,需 clonenode(true) 克隆后插入;插入前须确保 template 已挂载 dom,否则 content 为空;ie11 不支持 content 属性,需 polyfill 或降级处理。

template.content 返回的是 DocumentFragment,不能直接 appendChild
直接对 template.content 调用 appendChild 会静默失败(或抛错:「Node.insertBefore: Node is not child of this container」),因为 content 是一个 DocumentFragment,它本身不参与 DOM 树,且其子节点在首次被移动后就从 fragment 中被移除——后续再试图重复插入同一节点会无效。
正确做法永远是先克隆:
-
template.content.cloneNode(true)才能得到可多次使用的节点副本 -
cloneNode(false)只克隆第一层(适合只取子元素、不要深层文本节点的场景) - 注意:
cloneNode()对DocumentFragment有效,但对普通Element克隆后仍是 Element,类型不变
插入前必须确保 template 已在 DOM 中(否则 content 为空)
如果 <template></template> 是通过 innerHTML 动态写入或 JS 创建后未 append 到文档,其 content 里没有解析后的子节点——即使 HTML 字符串看起来是对的,content.childNodes.length 也可能为 0。
验证方式:
- 打印
template.content.children.length,应大于 0 - 确保 template 元素已挂载(例如:
document.body.appendChild(template)或已存在于初始 HTML 中) - 动态创建时,用
document.createElement('template')后必须调用template.innerHTML = '...',再使用content
克隆后插入需指定父容器,不能直接 insertBefore(document.body)
DocumentFragment 克隆体仍是 fragment,它没有 parentNode,也不能作为 insertBefore 的第一个参数直接插到 document 级别位置。常见错误写法:document.body.insertBefore(frag, null) —— 这实际可行,但容易误写成 document.insertBefore(frag, null),后者会报错「HierarchyRequestError」。
安全插入方式:
- 用
parentElement.appendChild(frag)(最常用,末尾插入) - 用
parentElement.insertBefore(frag, referenceNode)(需确保referenceNode是parentElement的直属子节点) - 避免对
document或document.documentElement直接操作 fragment,除非明确目标是document.head或document.body
IE11 不支持 template.content(需 polyfill 或降级处理)
IE11 识别 <template></template> 标签但不实现 content 属性,访问时返回 null。若需兼容,要么放弃 template,要么加判断:
const frag = template.content ? template.content.cloneNode(true) : document.importNode(template, true).content.cloneNode(true);
但更现实的做法是:只在现代浏览器中用 template,IE 场景改用 script type="text/template" + innerHTML 解析,或引入 template-polyfill。
真正容易被忽略的是:克隆操作本身不触发任何生命周期(比如自定义元素的 connectedCallback),只有插入到真实 DOM 后才触发——所以别在 cloneNode 后立刻查 offsetHeight 或监听事件,得等 append 完。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











