template标签必须作为body或head的直接子元素,其内容需通过cloneNode(true)克隆content属性插入,否则失效;克隆后需手动绑定事件、设值,避免ID重复;IE不支持,需降级为字符串模板。

template 标签本身不渲染,但必须放对位置
直接把 <template> 写在 <table> 里、<script> 里或自闭合标签后,浏览器会自动挪走甚至丢弃内容——结构就毁了。它只允许出现在 <body> 或 <head> 直接子节点位置。
- ✅ 正确:
<body><template id="card"><div class="card">...</div></template></body> - ❌ 错误:
<table><template><tr><td>...</td></tr></template></table>→ 浏览器会把它提到<table>外 - ❌ 错误:
<script><template>...</template></script>→ 解析失败,content 为空
克隆 content 才能插入,不能直接 append template 元素
template 元素自己没子节点,template.children 是空的,template.innerHTML 永远是空字符串。真正内容藏在只读的 content 属性里,且是个 DocumentFragment,只能用一次。
- ❌ 错误:
container.appendChild(template)→ 插入的是空元素 - ❌ 错误:
container.appendChild(template.content)→ 第二次调用就失效(fragment 被移走) - ✅ 正确:
container.appendChild(template.content.cloneNode(true))→ 每次都深克隆 - ⚠️ 注意:
cloneNode(false)只克隆顶层,嵌套结构全丢;必须加true
模板里的表单和事件不会自动生效
克隆出来的 <input> 还带着初始 value,但用户输入值、焦点状态、选中状态全丢失;内联 onclick 不起作用,<script> 不执行,<img src> 不发请求。
- 手动设值:
clone.querySelector('input').value = data.value - 手动绑定事件:
clone.querySelector('.submit-btn').addEventListener('click', handler) - 避免用 ID:
template里写id="email"→ 克隆多次后 DOM 出现重复 ID,用class或data-*替代 -
<slot>可用,但需配合name属性和外部元素的slot属性,不是所有场景都适用
IE 不支持,降级方案别硬扛 polyfill
IE 完全没有 template.content,连 document.createElement('template') 创建的元素也没有 content 属性。强行用 polyfill 很容易漏掉 cloneNode(true) 的完整语义。
立即学习“前端免费学习笔记(深入)”;
- 现代项目:直接不兼容 IE,省事又安全
- 必须兼容:改用构建时预编译 + 字符串模板(如
const tpl = (d) => `<div>${d.name}</div>`),再配合textContent赋值防 XSS - 别信“一行代码兼容”:真实 polyfill 需模拟
DocumentFragment行为、重写cloneNode、处理slot,维护成本高
真正容易被忽略的是:你每次都要重新 cloneNode(true),缓存 template.content 直接反复插入,结果就是第一次成功、后面全空白。



















