template 是惰性 dom 片段仓库,内容解析但不渲染、不执行脚本、不加载资源;必须通过 clonenode(true) 克隆 content 后插入,且需重设表单 id/name/for 以确保功能正常。

template 标签不是占位符,也不是用来“藏 HTML 字符串”的容器——它是个原生的惰性 DOM 片段仓库,内容被解析但不渲染、不执行脚本、不加载图片。直接写进 HTML 就生效,但必须用 JavaScript 克隆后才能插入页面。
template.content 是唯一合法入口,innerHTML 永远为空
你永远拿不到 template.innerHTML 的内容,它恒为 "";template.children 也永远是空 NodeList。浏览器把真实内容封装在只读的 DocumentFragment 里,藏在 content 属性中。
- ✅ 正确:
const frag = document.querySelector('#item').content; - ❌ 错误:
template.innerHTML.replace(...)、template.firstElementChild、Array.from(template.childNodes) - ⚠️ 注意:
frag是“剪切语义”——首次appendChild(frag)后,frag就空了,第二次再 append 会静默失败
必须 cloneNode(true),别信 importNode 或浅克隆
cloneNode(true) 是目前最稳、最兼容的深克隆方式。虽然 document.importNode(template.content, true) 语义更准,但在 Safari 15.4 之前对 fieldset 或带 required 的表单控件有 bug,checkValidity() 可能返回 false 即使值完全合法。
- ✅ 推荐:
const instance = template.content.cloneNode(true); - ❌ 避免:
cloneNode(false)—— 只克隆空 fragment 容器,没子节点 - ⚠️ 表单场景必做:重设
id、name、for,否则多个实例 label 点击无效、提交字段覆盖 - ? 建议用
crypto.randomUUID().slice(0, 8)生成唯一 ID,别用Math.random()
template 不能随便放,嵌套位置有硬限制
template 必须直接位于 或 内,否则浏览器会静默移除或错位解析。尤其注意它不能出现在语义受限的父容器中:
- ❌ 错误位置:
<table><template><tr><td></td></tr></template></table>→<template></template>被提到<table> 外,<code><tr> 还可能被自动包进 <code><tbody> <li>✅ 正确位置:<code><template id="card"><div class="card">...</div></template> - ⚠️ 小陷阱:
<template></template>内部可以写语义非法结构(如<p></p> <div>xxx</div>),因为不走标准渲染流程,只做解析挂起 - ✅ 正确做法:样式写外部 CSS,用 class 控制;交互逻辑统一在克隆后绑定事件
- ❌ 不要依赖:试图靠内部
<script></script>初始化、或靠<style></style>隔离样式作用域 - ⚠️ 图片/iframe 不会预加载,但一旦克隆并插入 DOM,就会立即触发请求 —— 若需懒加载,应延迟赋值
src
别往 template 里塞 style/script,它们不会生效
<template><style>.x{color:red}</style>
<script>console.log(1)</script></template> 中的 <style></style> 不会应用,<script></script> 不会执行,控制台也不会报错——这是设计使然,不是 bug。
真正容易被忽略的是:模板是否中立。如果里面写死 class="card card--tech" 或 <h1>最新技术动态</h1>,换到用户列表页就得重写——结构和业务语义耦合越紧,后期改起来越像在拆炸弹。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











