必须克隆 template.content 后插入:直接 appendchild(template) 或 template.content 均失败;克隆需带 true 参数;高频渲染应先聚合成 documentfragment 再批量插入;克隆后须重设 id、更新 for 属性、重新绑定事件;ie 需降级处理;img/video 等资源在插入后才触发加载。

template.content.cloneNode(true) 是插入前唯一合法起点
直接 appendChild(template) 或 appendChild(template.content) 都会失败:前者把 <template></template> 元素本身移走,后者第一次插入后 template.content 就变为空 fragment,第二次调用静默无效。浏览器规范强制要求——必须先克隆内容,再插入。
-
template.content是只读的DocumentFragment,不能当普通节点用 -
cloneNode(true)必须加true,否则只复制空容器,内部结构全丢 - 克隆结果是独立 DOM 片段,可安全多次插入同一父节点或不同父节点
插入目标父节点时要避开重排性能陷阱
高频渲染(比如列表 50+ 条)时,逐条 appendChild(clone) 会触发多次 layout,卡顿明显。正确做法是用 document.createDocumentFragment() 中转:
- 创建 fragment:
const frag = document.createDocumentFragment() - 循环克隆并
frag.appendChild(clone) - 最后一次性
parent.appendChild(frag) -
frag插入后自动清空,不可复用,每次都要新建
插入后必须手动处理 ID、name 和事件绑定
克隆体保留原始 id、name、for 属性,不处理会导致 document.getElementById() 失效、label[for] 点击无响应、<input type="radio"> 组互斥异常:
- 重设 ID:
clone.querySelector('[id]').id = 'item-' + counter++ - 同步更新
label[for]:clone.querySelector('label').htmlFor = clone.querySelector('input').id - 事件不能继承,需重新绑定:
clone.querySelector('button').addEventListener('click', handler),或改用父级事件委托
IE 不支持 template,降级方案要提前检测
typeof HTMLTemplateElement === 'undefined' 为 true 时,说明浏览器不支持。此时不能依赖 template.content,常见降级方式:
- 用
<script type="text/template"></script>包裹 HTML 字符串,再用innerHTML解析(注意 XSS 过滤) - 用
<div style="display:none"> 替代,但语义弱、易被误操作或 CSS 干扰 <li>避免在模板内写 <code><script></script>或<style></style>,克隆后它们不会执行/生效,强行注入风险高
真正容易被忽略的是:克隆后
<img src> 才开始加载、<video autoplay></video> 才启动播放、<input value="x"> 的当前值仍是初始值——这些都不是“渲染完成”的信号,而是 DOM 插入后的副作用。需要监听插入时机(如 connectedCallback)再做后续动作。











