是纯dom片段容器,浏览器解析时跳过其内容,不渲染、不执行脚本;需用document.importnode安全克隆并手动映射数据才能实现组件化功能。

<template></template> 不是组件,只是 DOM 片段容器
浏览器解析到 <template></template> 时直接跳过其内容,不渲染、不执行脚本、不加载图片、不触发任何事件。它不是 Vue 的 <template></template>,也不是 Web Component 的 <slot></slot>,更不是 React 的 JSX 片段。写完就放那儿,页面上什么都不会出现——这是最常被误判的起点。
- 直接用
innerHTML往<template></template>里塞字符串,会破坏它的“惰性”,让它退化成普通div,失去克隆安全性和状态保留能力 - 模板内写
{{title}}或v-if,纯 HTML + JS 完全无视,只会原样显示在页面上 - 多次使用同一模板却硬编码
id="card-1",会导致 ID 冲突,后续document.getElementById()只取到第一个
document.importNode() 是安全克隆的唯一可靠方式
cloneNode(true) 看似能复制结构,但对表单控件(如 <input checked>、<select></select>)的状态丢失严重;而 document.importNode(tmpl.content, true) 才能保留选中态、滚动位置、焦点等运行时状态,尤其在 Shadow DOM 或动态插入场景下不可替代。
- 获取模板:const tmpl = document.getElementById('
card-template') - 克隆内容:const fragment = document.importNode(tmpl.content, true)
- 填充数据:遍历
fragment.querySelectorAll('[data-bind]'),按data-bind="title"映射到node.textContent = data.title - 插入节点:用
container.appendChild(fragment),别用innerHTML覆盖已有 DOM,否则会销毁事件监听器和状态
<template></template> 配合 IntersectionObserver 才真正提升首屏性能
display: none 的区块仍参与 CSSOM 构建与布局计算,对长图文页或商品列表后半截内容,这会显著拖慢首屏解析速度。而把非首屏内容包在 <template></template> 中,配合 IntersectionObserver 检测进入视口后再克隆插入,才能真正延迟 DOM 构建。
- 必须将
<template></template>放在顶层或<tbody> 外,否则浏览器可能因解析顺序异常而忽略它 <li>观察器回调中调用 <code>importNode+ 填充 +appendChild,不要提前解析模板内容 - 若需响应式更新,缓存首次生成的 fragment,后续只更新 textContent 或 dataset,避免重复克隆开销
真正容易被忽略的是:<template></template> 本身不带任何逻辑,所谓“组件化”全靠 JS 实现;它只是个轻量级的结构占位符,不是运行时基础设施。脱离手动克隆和数据映射,它连一个可交互的按钮都出不来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











