template 标签本身不提速,真正起作用的是它强制走「预解析+深克隆+批量插入」路径;clonenode(true) 比 innerhtml 快因跳过 html 解析与布局重排,实测快 2–3 倍;正确做法是用 documentfragment 中转并单次插入,避免逐条 append 导致重排卡顿。

template 标签本身不提速,真正起作用的是它强制你走上「预解析 + 深克隆 + 批量插入」这条路径——绕开字符串拼接和逐个 createElement 的性能陷阱。
为什么 template.content.cloneNode(true) 比 innerHTML 快
-
innerHTML每次都要重新解析 HTML 字符串,触发完整 DOM 构建、样式计算、布局重排;100 条数据就可能触发 100 次 layout。 -
template.content是浏览器一次性解析好的DocumentFragment,cloneNode(true)只是内存复制节点树,不走 HTML 解析器,也不触发样式或布局。 - 实测(Chrome 128+):千条列表项渲染,
template.content.cloneNode(true)比字符串拼接快 2–3 倍,且内存分配更稳定。
常见错误现象:
- 直接
el.innerHTML += template.innerHTML—— 完全放弃template优势,还引入 XSS 风险 - 在循环里反复
el.appendChild(template.content)—— 第二次起静默失败,列表缺项
大规模列表必须用 DocumentFragment 中转
- 循环中每轮都
container.appendChild(cloned),等于每轮都触发一次重排重绘。 - 500 条数据 ≈ 500 次 layout,页面明显卡顿;1000 条基本不可交互。
正确做法:
- 创建临时容器:
const frag = document.createDocumentFragment() - 循环体内:克隆 → 填值 →
frag.appendChild(cloned) - 循环结束后,只调一次
container.appendChild(frag)
注意:frag 不在主 DOM 树中,querySelector 查不到它,也不触发任何样式计算——这是它能扛住批量插入的关键。
克隆后填值必须避开 innerHTML
- 模板里有用户输入内容?直接
el.innerHTML = data.title等于主动执行未过滤的 HTML,XSS 风险拉满。 -
innerHTML还会清空已绑定事件、重置表单控件状态(比如input的光标、选中范围)。
安全填值方式:
- 纯文本 →
el.querySelector('.title').textContent = data.title - 表单控件 →
el.querySelector('input').value = data.inputValue(不是textContent) - 富文本 → 先转义:
data.html.replace(/&/g, '&').replace(/, ',再塞进 <code>innerHTML
别忘了:模板里写的 <script></script> 或 <style></style>,克隆后依然不执行、不生效——别指望“活”过来。
大规模列表滚动前得认清临界点:即使用了 template + cloneNode(true) + DocumentFragment,一次性渲染 10000 条仍会卡顿。这不是写法问题,是浏览器对真实 DOM 节点数量的硬性响应延迟。真要撑住万级列表,得上虚拟滚动——template 只负责把“每一帧该画什么”这件事干得又快又干净。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











