<template> 是浏览器原生模板机制,内容默认不渲染不执行;需作为顶层或 <body> 直接子级使用,克隆应调用 .content.cloneNode(true),填充文本优先用 textContent 防 XSS,旧版浏览器需兼容处理 content。

直接用 <template> 标签声明片段,不渲染、不执行脚本
<template> 是浏览器原生支持的模板机制,它的内容默认不会被解析或执行——script 不运行、img 不加载、iframe 不发起请求。这和把 HTML 写在 textarea 或注释里有本质区别。
必须注意:<template> 不能嵌套在其他元素内部(比如不能放在 <div> 里),否则 template.content 可能为空;它得是文档顶层节点,或者至少是 <body> 的直接子级。
- 定义时用唯一
id,方便后续 JS 查找:<template id="user-card"><div class="card">...</div></template> - 克隆必须用
.content.cloneNode(true),直接.innerHTML会丢失事件绑定和部分 DOM 属性 - 如果模板里含
<slot>,需配合自定义元素使用,单独用<template>时<slot>不生效
用 JavaScript 实例化模板时,手动填充数据比 innerHTML 更安全
很多人习惯写 el.innerHTML = templateString,但对 <template> 来说,更推荐先克隆再遍历赋值——尤其当数据来自用户输入或 API 时,能天然避免 XSS。
例如,不要这样写:card.querySelector('h3').innerHTML = userData.name(若 name 含 <script> 就危险);而应写:card.querySelector('h3').textContent = userData.name。
立即学习“前端免费学习笔记(深入)”;
- 优先用
textContent填充文本内容 - 需要渲染富文本时,才用
innerHTML,且务必先做白名单过滤(如只允许<strong>、<em>) - 图片、链接等属性用
setAttribute()设置,而非拼进字符串 - 避免在模板中硬编码 ID 或 class 名用于 JS 查询——容易因重复实例导致冲突,改用相对定位(如
card.firstElementChild)或data-属性标记
多个模板共用一套 JS 工厂函数,但要注意作用域污染
你可能为 header、card、modal 各写一个 <template>,再统一用类似 render(templateId, data) 的函数处理。这没问题,但别让工厂函数直接操作全局 document。
常见错误是:函数里写 document.getElementById('main'),结果在 Web Component 或 iframe 场景下失效;或者多次调用后,所有实例都往同一个容器追加。
- 工厂函数最好接收目标容器元素作为参数,而不是硬编码选择器
- 如果模板含交互逻辑(如按钮点击),事件监听器应在克隆后绑定到该实例,别用委托到
document(易泄漏) - 不要在工厂函数里修改传入的
data对象——浅拷贝或解构取值更稳妥 - 模板内避免依赖外部 CSS 类名或 JS 变量,否则复用到新项目时容易“断链”
IE11 能用,但 Edge 12–78 和 Safari 9–13.1 有 content 兼容性坑
<template> 在 IE11 中可用,但旧版 Edge(12–78)和 Safari(9–13.1)对 template.content 返回值的处理不一致:有些返回空 DocumentFragment,有些不支持 cloneNode(true) 深克隆。
如果你的目标环境包含这些旧浏览器,别只靠 if (template.content) 判断,得加一层 fallback:
- 检测
template.content.nodeType === 11(DocumentFragment 的 nodeType) - 若失败,退回到
document.createElement('div')+innerHTML方案(牺牲安全性换兼容) - 不要依赖
template.innerHTML——它始终是空字符串,永远读不到内容 - 构建时可通过 Babel 插件自动注入 polyfill,但 runtime 检测更可靠
真正容易被忽略的是:模板里的 <style> 标签在克隆后不会自动生效,得手动提取并插入 <head>,否则样式隔离就失效了。



















