template标签天生懒渲染,需通过content.clonenode(true)访问并克隆内容;可视区懒加载应结合intersectionobserver与documentfragment批量插入;填值优先用textcontent/value,避免innerhtml引发xss及事件丢失。

template 标签本身不支持“懒渲染”这个概念——它天生就是懒的。所谓“懒渲染”,其实是你控制克隆和插入时机的策略,不是标签自动提供的能力。
为什么 template.content.cloneNode(true) 是唯一可靠入口
很多人卡在第一步:用 document.querySelector('template').innerHTML 拿不到内容,返回空字符串。这是因为 template 的真实内容被包裹在 DocumentFragment 里,只能通过 content 属性访问。
-
template.innerHTML始终为空,永远别用 -
template.textContent返回所有文本(含换行缩进),但无法操作结构 - 必须走
template.content.cloneNode(true),否则后续所有节点操作都失效 - 不加
true参数是浅克隆,子元素事件监听器、表单状态、input光标位置等全丢
滚动触发克隆:实现可视区懒加载
把模板克隆推迟到元素进入视口时执行,能显著减少首屏 DOM 节点数和内存占用。适用于长列表、商品瀑布流等场景。
- 给每个待渲染容器预留一个占位
div,带data-template-id和data-item-id - 用
IntersectionObserver监听占位节点是否进入视口 - 触发时才调用
cloneNode(true)→ 填值 → 插入,同时移除占位节点 - 避免在
observe回调里直接操作 DOM,先缓存克隆结果再批量 append
批量插入必须用 DocumentFragment,否则性能崩得快
循环里每轮都 container.appendChild(cloned),等于让浏览器反复重排重绘。100 条数据可能就明显卡顿;500 条基本卡死。
- 先
const frag = document.createDocumentFragment() - 循环体内:克隆 → 填值 →
frag.appendChild(cloned) - 循环结束后,只调一次
container.appendChild(frag) -
frag是轻量中间容器,不能被querySelector查到,也不在 DOM 树中
填值时别碰 innerHTML,优先用 textContent/value
用 innerHTML 拼接字符串填值,等于主动引入 XSS 风险,还会意外销毁已绑定的事件监听器(比如模板里原本有 button,克隆后 onclick 就没了)。
- 纯文本内容:
el.querySelector('.title').textContent = data.title - 表单控件:
el.querySelector('input').value = data.value,不是textContent - 需要保留 HTML 结构?先对用户输入做转义(如
text.replace(/&/g, '&')),再塞进innerHTML - 模板中含
<script></script>或<style></style>?cloneNode(true)不会执行脚本,也不会重复加载样式
真正容易被忽略的是:模板里的 slot 不生效,data- 属性能留但不会自动映射为 JS 对象属性,而多次克隆后未清理的事件监听器或定时器,会在页面生命周期中持续存在。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











