template 是惰性 DOM 容器,内容仅可通过 template.content 访问;克隆需用 cloneNode 或 importNode;插槽仅在 Shadow DOM 中生效;IE 需用 script[type="text/template"] 降级,且须防 XSS。

template 标签本身不提供“模板系统”,它只是一个惰性 DOM 容器。所谓“高效的内容模板系统”,是你用它 + 明确的实例化逻辑 + 合理的数据绑定方式搭出来的,不是开箱即用的框架。
为什么不能直接 innerHTML 或 children 访问 template 内容
很多人第一次用 template 就卡在这儿:template.innerHTML 返回空字符串,template.children 是空 NodeList —— 因为内容被封装在只读的 DocumentFragment 里,只能通过 template.content 拿到。
- 直接
appendChild(template.content)只能插入一次,第二次会失败(content是移动语义,不是复制) - 必须用
cloneNode(true)或document.importNode(template.content, true)才能复用 - 如果模板含
<style>,样式会生效但作用域是全局的;想局部化,得配合 Shadow DOM
如何安全填充表单控件和事件
克隆后直接改 value、checked、textContent 没问题,但要注意几个易错点:
-
<input id="email">克隆后多个实例会重复 ID —— 必须重设id或删掉(用name或dataset区分) - 内联
onclick在template里不会执行,也不该依赖它;事件要手动addEventListener到克隆节点上 -
<select>的selectedIndex不会被克隆继承,得显式设置value或遍历options - 图片
src不会预加载,但克隆后插入 DOM 就会立即请求 —— 若需懒加载,得等插入后再赋值
slot 插槽怎么用才不踩坑
<slot> 是解耦结构与内容的关键,但它的行为和直觉有偏差:
立即学习“前端免费学习笔记(深入)”;
- 未命名
<slot>只能接收模板外部的“默认内容”,且仅在template被用于ShadowRoot时才起作用;纯template+cloneNode场景下,<slot>会被当普通标签处理,不自动分发 - 命名插槽(
<slot name="header">)需要你在克隆后,手动创建元素并设置slot="header"属性,再 append 进克隆体 -
<slot>内容不会出现在template.content的子树中 —— 它是运行时由宿主元素决定的,所以别指望用querySelector提前定位 slot 里的东西
兼容性与降级的实际底线
现代浏览器全支持 template(Chrome 26+ / Firefox 22+ / Safari 9+ / Edge 13+),但 IE 完全不支持。如果你必须兼容 IE:
- 不要用
document.createElement('template')判断,IE 会创建但无content属性 —— 正确检测是!!document.createElement('template').content - 降级方案不是“模拟
content”,而是改用<script type="text/template">+innerHTML,但必须严格转义数据防 XSS - polyfill(如
template-polyfill)只补 API 行为,不解决 Shadow DOM 或 slot 等高级特性,别指望它让 IE 支持命名插槽
最常被忽略的一点:模板内容虽“惰性”,但仍需是合法 HTML 结构。比如把 <tr> 直接塞进 template 没问题,但若把它放进一个没包裹 <tbody> 的 <table> 里,解析时就会被浏览器自动修正甚至丢弃 —— 这类结构错误不会报错,但克隆出来就不是你想要的 DOM 树。



















