<template>标签内容不生效是因为其本质是惰性DOM片段,浏览器解析时跳过执行:图片不请求、脚本不运行、样式不计算、表单状态不保留;必须通过document.importNode(tmpl.content, true)或tmpl.content.cloneNode(true)克隆后手动填充、绑定事件并插入DOM才能显示。

<template> 标签本身不渲染、不执行脚本、不加载资源,不能直接当组件用——它只是个“待命的 DOM 片段”,必须配合 JS 手动克隆、填充、挂载,否则页面什么都不会显示。
为什么<template>内容完全不生效
浏览器解析时会跳过 <template> 内部所有节点:图片不请求、<script> 不执行、data-* 属性不被读取、表单控件状态(如 <input checked>)也不保留。常见错误是把它当 Vue 的 <template> 或 Web Component 的 <slot> 直接写进去,结果 DOM 里空空如也。
- 直接赋值
innerHTML = tmpl.innerHTML会丢失表单元素当前状态(比如用户已勾选的复选框) - 用
cloneNode(true)复制后插入,<script>和<style>不会自动执行或生效 - 模板里写
{{title}}这类插值语法,纯 HTML + JS 不识别,必须手动字符串替换或 DOM 操作
如何安全克隆并填充<template>内容
核心是用 document.importNode() 替代 cloneNode(),它能保留表单控件状态、正确处理 <select> 选项、兼容 Shadow DOM 场景。
- 获取模板:
const tmpl = document.getElementById('card-template') - 克隆内容:
const fragment = document.importNode(tmpl.content, true)(第二个参数true表示深克隆) - 查找绑定点:
fragment.querySelectorAll('[data-bind]'),根据data-bind="title"找到对应节点 - 填充数据:对文本节点用
node.textContent = data.title;对 HTML 内容用node.innerHTML = data.content(注意 XSS 风险) - 挂载:
container.appendChild(fragment),不要用innerHTML覆盖已有结构,否则会销毁事件监听器和表单状态
怎么让<template>支持传参和复用
纯 <template> 没有生命周期或属性监听机制,“传参”本质就是调用 JS 工厂函数时传入对象,再由 JS 映射到 DOM 节点。
立即学习“前端免费学习笔记(深入)”;
- 模板中用语义化
data-bind属性(如data-bind="author-name"),比 class 名更易维护、不易冲突 - 工厂函数返回真实 DOM 节点(
DocumentFragment),而非字符串,避免重复解析 - 若需响应式更新,得手动缓存首次生成的节点,后续只更新
textContent或dataset值,不重新克隆 - 禁止在模板内硬编码 ID(如
id="card-1"),多次使用会导致 ID 重复,破坏 CSS 选择器和document.getElementById()查询
<template> 和 Web Components 的边界在哪
它不提供封装性、无样式隔离、无属性响应式、无生命周期钩子——所谓“模块化”,仅止于结构复用。真正需要样式隔离、属性监听、跨项目分发时,必须转向 customElements.define()。
容易被忽略的是:哪怕只用 <template>,也得警惕克隆后节点未挂载就操作 DOM(比如在 connectedCallback 外读取 template.content),此时取到的往往是空文档片段;还有,开发时若用 file:// 协议打开页面,fetch('nav.html') 会因 CORS 被拒,必须起本地服务(npx serve 或 vite)。



















