template.content.cloneNode(true)是唯一可用入口,因template.innerHTML恒为空,真实内容在content属性的DocumentFragment中,须深克隆才能复用且不破坏原模板。

template.content.cloneNode(true) 是唯一能用的入口
很多人一上来就写 document.querySelector('template').innerHTML,结果拿到空字符串——因为 template.innerHTML 永远为空,浏览器根本不会把内容塞进去。真实内容藏在 content 属性里,它返回的是一个 DocumentFragment,不能直接插入多次,也不能直接修改。
必须用 cloneNode(true):不加 true 是浅克隆,子节点文本、事件监听器、input 的当前值全丢;加了才真正复制结构+内容+属性,且不影响原模板。
-
template.content只能被插入一次,第二次appendChild就什么也不发生 - 别用
document.importNode(content, true)代替——它在含表单元素时更安全,但多数场景下cloneNode(true)更直白、兼容性一致 - 克隆后若要改
id,得手动设:clone.querySelector('[id]').id = 'item-1',否则所有实例 ID 冲突
填值别碰 innerHTML,优先用 textContent 和 value
模板里写 <h3 class="title">{{title}}</h3> 是常见做法,但替换时千万别用 el.innerHTML = data.title。这会清空原有事件绑定(比如按钮上的 onclick),还可能引入 XSS(如果 data.title 来自用户输入)。
- 纯文本内容:用
el.querySelector('.title').textContent = data.title - 表单控件:
el.querySelector('input').value = data.value,不是textContent,否则光标位置、输入状态全丢 - 真需要渲染 HTML 片段?先转义:
text.replace(/&/g, '&').replace(/, '<'),再塞进innerHTML - 模板里的
<script>或<style>克隆后不会执行或重复加载,别指望靠它动态注入逻辑
批量插入必须走 DocumentFragment,否则页面卡死
循环渲染 100 条数据时,每轮都 container.appendChild(cloned),等于让浏览器反复重排重绘。实测 500 条基本卡顿到交互失灵。
立即学习“前端免费学习笔记(深入)”;
- 正确做法:创建
const frag = document.createDocumentFragment(),循环里只往frag里appendChild - 循环结束,只调一次
container.appendChild(frag) -
frag是轻量中间容器,不在 DOM 树中,querySelector查不到它,放心用 - 注意:每次克隆都得是独立副本——漏掉
cloneNode(true),所有项共用同一节点引用,改一个就全变
data- 属性能留,slot 和事件绑定得自己管
template 不是 Web Components 容器,它没挂载到 Shadow DOM,所以 <slot name="header"></slot> 这种写法完全无效。用 querySelector('[slot="header"]') 也查不到东西。
-
data-id、data-index这类属性能保留在克隆节点上,但不会自动变成 JS 对象属性,得手动读取 - 模板里写的
onclick="handleClick()"在克隆后失效——事件没绑定到新节点,得用clone.querySelector('button').addEventListener('click', handler)补上 - 回收复用节点时(比如滚动列表),必须手动清空
textContent和value,否则残留内容会在下次显示时意外出现 - IE11 不支持
node.remove()自动清理事件,回收前务必显式调用removeEventListener,否则内存泄漏
容易被忽略的是:克隆不是“复制一次就能反复填值”,每次渲染都得重新 cloneNode(true),然后单独填值、单独绑定事件。没有捷径,也没有自动响应机制。



















