<template>标签不生成任何DOM节点,内容以DocumentFragment形式暂存,必须用cloneNode(true)深克隆后插入才能生效;内部脚本不执行、资源不加载、样式不计算。

template 标签不是隐藏层,也不是备用容器——它根本不会生成任何 DOM 节点,document.getElementById 永远查不到里面写的 id,querySelector 也找不到内部元素,脚本不执行、图片不加载、样式不计算。这是它的设计本质,不是 bug。
为什么 document.getElementById 找不到 template 里的元素
因为 template 的内容在解析时被浏览器当作“蓝图”暂存为 DocumentFragment,完全不挂载到 DOM 树中。它不像 div style="display:none" 那样已存在 DOM 里只是不可见。
- 写
<template id="card"><div id="item">xxx</div></template>后,document.getElementById("item")返回null是正常行为 - 想操作内部结构,必须先通过
template.content获取片段,再用cloneNode(true)创建可插入的副本 - 直接
appendChild(template.content)只能成功一次;第二次会失败,因为content是“单次消耗品”
template.content.cloneNode(true) 必须加 true 参数
cloneNode() 默认是浅克隆(false),只复制顶层 DocumentFragment 容器,不包含子节点。实际插入后页面空白,控制台也无报错,极易误判为模板没生效。
- 正确写法:
const fragment = tmpl.content.cloneNode(true) - 错误写法:
tmpl.content.cloneNode()或tmpl.content.cloneNode(false) - 若模板内含
<slot>或需事件绑定,浅克隆会导致子元素丢失或事件无法触发 - 现代框架(如 Vue)内部也依赖深克隆逻辑,手动实现时别跳过这个参数
template 中的 script 和 style 怎么处理
template 内的 <script> 标签不会自动执行,<style> 也不会立即应用——这是安全机制,但也是容易忽略的坑。
立即学习“前端免费学习笔记(深入)”;
- 需要运行脚本时,得手动创建新
script元素,设置textContent或src,再插入克隆后的 fragment 中 - 内联
<style>插入后会全局生效,可能污染主文档样式;建议改用class+ 外部 CSS,或配合 Shadow DOM 封装 - 不要在
template里写onclick="doSomething()":函数作用域不在当前上下文,且克隆后绑定失效 - 动态绑定推荐用
element.addEventListener,在克隆后、插入前完成
IE 和旧版 Safari 需要 polyfill 吗
2026 年主流浏览器(Chrome 120+、Firefox 115+、Safari 17+、Edge 120+)已原生支持 template,但 IE 完全不支持,iOS 14.5 及更早 Safari 存在 content 返回空 fragment 的 bug。
- 若需兼容 iOS ≤14.5,可用
document.importNode(tmpl.content, true)替代cloneNode(部分旧引擎对后者支持不稳定) - IE 用户占比极低,真要支持,建议用
script[type="text/template"]回退,但注意 XSS 风险和 HTML 字符转义 - 检查支持性只需一行:
typeof HTMLTemplateElement !== 'undefined',不必引入整套 polyfill
最常被漏掉的一点:模板内容不是“延迟渲染”,而是“从未构建”。它不占布局空间、不触发重排、不消耗内存——但代价是你必须亲手接管所有实例化逻辑,包括数据填充、事件注册、资源加载时机。没有自动绑定,也没有响应式更新,这就是原生 template 的边界。



















