<template> 标签不会被浏览器直接渲染,因其内容被浏览器视为“惰性模板”,不执行脚本、不加载资源、不绑定数据;必须通过 document.importNode(tmpl.content, true) 克隆并挂载才能生效,且不支持响应式、属性传参或生命周期,仅适用于静态、低频、非交互场景。

为什么<template>不能直接当组件用
它根本不会被浏览器解析——内容跳过渲染、脚本不执行、图片不加载、data-属性不绑定。你写个<template id="card"><img src="logo.png"><script>console.log(1)</script></template>,页面里啥都看不到,控制台也没输出,Network 面板里 logo.png 也不会发请求。
常见误操作是把它当 Vue 的 <template> 或 Web Component 的 <slot> 用,结果 DOM 里空空如也。更隐蔽的坑是:用 innerHTML = tmpl.innerHTML 直接塞进容器,会丢掉 <input checked> 的选中态、<select> 的当前选项,甚至破坏表单控件的引用关系。
如何安全克隆并填充<template>内容
必须用 document.importNode(tmpl.content, true),而不是 cloneNode(true)。前者能保留表单状态、正确处理 <select> 和 <textarea> 的值,且兼容 Shadow DOM;后者只是浅层复制 DOM 结构,不带运行时状态。
- 获取模板:
const tmpl = document.getElementById('card-template') - 克隆内容:
const fragment = document.importNode(tmpl.content, true) - 填充数据:遍历
fragment.querySelectorAll('[data-bind]'),按data-bind="title"找节点,用textContent或innerHTML赋值(注意 XSS) - 挂载:
container.appendChild(fragment),别用innerHTML覆盖已有结构,否则会清空事件监听器和已绑定状态
<template>组件怎么支持“传参”和复用
它没有属性、没有生命周期、不监听数据变化。“传参”本质就是调用一个工厂函数,传入纯 JS 对象,JS 再手动映射到 DOM 节点。适合静态卡片、弹窗、表单项等低频、非响应式场景。
立即学习“前端免费学习笔记(深入)”;
- 模板里用
data-bind="author-name",别用class="author",避免样式类与逻辑耦合 - 工厂函数返回
DocumentFragment,不是字符串,省去重复解析开销 - 如需更新,缓存首次生成的节点,后续只改
textContent或dataset值,不重新克隆 - 禁止硬编码
id(如id="card-1"),多次实例化会导致 ID 冲突,影响 CSS 查询或getElementById
和 Web Components 相比,<template>方案的边界在哪
它不封装样式、不隔离作用域、不提供自定义元素注册机制,也不支持 Shadow DOM 样式穿透控制。所有样式靠全局 CSS,所有事件靠手动委托,所有逻辑靠外部 JS 管理。
真正需要封装性、样式隔离、生命周期钩子或跨框架复用时,就得上 customElements.define()。而 <template> + JS 工厂函数,只适合轻量级、项目内统一规范下的模块化组织——比如把页脚、侧边栏、通知条抽成 HTML 片段,由构建流程统一注入,再由少量 JS 实例化。复杂交互或长期维护的组件,别硬撑。



















