<p>原生 <template> 标签是浏览器内置、零依赖、防 XSS 的动态渲染起点,但需 JS 显式控制数据绑定与更新;它提供经校验的合法 HTML 片段,避免字符串拼接的 XSS 和 DOM 修正问题,克隆时应优先用 template.content.cloneNode(true) 并规范使用 data-* 属性绑定。</p>

原生 <template> 标签是浏览器内置、零依赖、防 XSS 的动态渲染起点,但不能直接绑定数据或自动更新——它只提供惰性 DOM 片段,所有逻辑必须由 JS 显式控制。
为什么不用字符串拼接而用 <template>
字符串拼接(如 innerHTML = '<div>' + name + '</div>')容易引入 XSS,且 HTML 结构不合法时会静默修正(比如把 <tr><div></div></tr> 改成无效 DOM),调试困难。而 <template> 内容在解析阶段就被校验为合法 HTML,template.content 返回的是完整 DocumentFragment,结构确定、无副作用。
常见错误现象:Uncaught TypeError: Cannot set property 'textContent' of null——多因克隆后没查到对应元素,本质是模板里写了 <td class="name"></td>,但 JS 里写成了 querySelector('.username') 拼错类名。
- 模板中不要写
id="xxx",克隆多次会导致 ID 重复,改用class或data-*属性定位 -
<template>里的<script>不会执行,<img src="x.jpg">也不会加载,这是安全前提,别指望它“预热”资源 - 若需样式隔离,必须配合
Shadow DOM,<template>本身不带作用域
cloneNode(true) 和 importNode 的区别
cloneNode(true) 是最常用方式,从 template.content 克隆出独立节点树;importNode 主要用于跨文档(比如 iframe)导入,日常前端开发几乎用不到。
立即学习“前端免费学习笔记(深入)”;
关键差异在于:克隆后的节点仍属于当前文档,可直接 appendChild;而 importNode 需显式指定是否深克隆,且常被误用于同文档场景,反而多此一举。
- 永远优先用
template.content.cloneNode(true),不要写template.cloneNode(true).content——后者克隆的是整个<template>元素,不是它的内容 - 克隆后记得清空旧数据:比如卡片模板里有
<button data-id="">,插入前必须赋值,否则留空可能触发意外行为 - 批量渲染时,先建
DocumentFragment,把所有 clone 追加进去,最后一次性appendChild,避免频繁重排
如何让 <template> 支持简单数据绑定
没有框架时,靠手动替换最稳妥。别用正则全局替换 {{key}},它会误杀 HTML 属性里的花括号(如 style="{{color}}")或注释。
推荐做法:用 querySelectorAll('[data-bind]') 或 [data-text] 等语义化属性标记绑定点。
const template = document.getElementById('user-card');
const clone = template.content.cloneNode(true);
<p>// 绑定文本
clone.querySelectorAll('[data-text]').forEach(el => {
const key = el.dataset.text;
el.textContent = data[key] ?? '';
});</p><p>// 绑定属性
clone.querySelectorAll('[data-attr]').forEach(el => {
const [attr, key] = el.dataset.attr.split(':');
el[attr] = data[key] ?? '';
});</p><p>container.appendChild(clone);-
data-text="name"表示填文本,data-attr="src:avatar"表示把data.avatar赋给src属性 - 避免在模板里写
onclick="doSomething()",事件一律用clone.querySelector('button').addEventListener动态绑定 - 如果数据含 HTML 字符串(如富文本),用
el.innerHTML = sanitize(data.html),绝不用textContent
真正难的不是克隆模板,而是管理状态同步和事件生命周期——比如克隆出的按钮被删掉后,对应事件监听器是否清除、异步请求是否取消,这些都得自己兜底。



















