template.content 是访问模板内容的唯一合法入口,其子节点不进入DOM树,必须通过 .content 获取 DocumentFragment;该属性只读,需用 cloneNode(true) 或 importNode(content, true) 深度克隆,且须手动绑定事件、注入样式。

template.content 是唯一能拿到模板内容的入口
直接写 <template id="card"><div>xxx</div></template> 后,document.getElementById("card").children 返回空数组,querySelector 也找不到内部元素——因为它的子节点根本没进 DOM 树。必须通过 .content 属性访问其包裹的 DocumentFragment,这是唯一合法出口。
常见错误是试图用 innerHTML 修改 template.content:它只读,赋值会静默失败。想动态生成结构,得先创建 DocumentFragment 或用 document.importNode()。
克隆必须用 cloneNode(true) 或 importNode(content, true)
cloneNode(true) 和 document.importNode(template.content, true) 效果一致,都深度复制所有子节点、文本、属性,但关键区别在于上下文:
-
cloneNode复制的是当前文档中的 fragment,适合同文档复用 -
importNode更安全,尤其在跨 iframe 或不同文档对象时不会报错 - 漏掉
true参数会导致只克隆顶层<template>元素本身,内容丢失 - 直接
appendChild(template)是移动操作,第二次调用会失效(节点已不在原处)
复杂骨架里含 script/style 会失效,别指望自动执行
<template> 内的 <script> 不执行、<style> 不生效、<img src> 不加载——这是设计使然,不是 bug。如果你模板里写了:
立即学习“前端免费学习笔记(深入)”;
<template id="modal">
<style>.modal { z-index: 1000; }</style>
<div class="modal"><button onclick="close()">X</button></div>
</template>
克隆插入后,样式不会应用,onclick 也不会绑定。正确做法是:
- 把样式抽到外部 CSS 文件或
<head>中 - 事件监听器必须在克隆后手动加:
clone.querySelector('button').addEventListener(...) - 避免内联 JS,否则克隆后仍是字符串,不会变成可执行逻辑
table 场景下 template 不能当直接子元素用
写成这样会出问题:
<table> <template><tr><td>A</td></tr></template> </table>
浏览器会自动把 <template> 提升到 <table> 外,破坏语义和结构。正确姿势是:
- 把
<template>放在<table>外(比如紧邻下方),再用 JS 插入到<tbody>内 - 或者改用
<tbody><template>...</template></tbody>,但注意<template>仍不能是<tr>的直接父级 - 最稳妥:模板只存
<tr>及以内结构,插入目标明确为tbody
真正容易被忽略的是:template 不是“预编译”,它不缓存节点、不优化解析、不管理状态——所有这些都得你手动做。克隆一次是一次新节点,想复用就得自己建池子、清事件、重置表单值。否则看着结构对了,点两下按钮就失灵。



















