不能直接用 innerhtml 拼接列表项,因其触发完整 dom 重建、丢失事件绑定、破坏焦点、易 xss 且性能随长度线性下降;而 预解析结构、克隆 documentfragment,渲染更快更安全。

为什么不能直接用 innerHTML 拼接列表项
直接拼字符串再赋值给 innerHTML 看似简单,但会触发完整 DOM 重建、丢失事件绑定、破坏焦点状态,且容易 XSS(尤其未转义动态内容时)。更关键的是:每次更新都要重新解析 HTML 字符串,性能随列表长度线性下降。
而 <template></template> 提前定义结构,浏览器只做一次解析;克隆的是已解析的 DocumentFragment,插入开销极低。实测千条数据渲染,template.content.cloneNode(true) 比字符串拼接快 2–3 倍(Chrome 128+)。
- 模板内容不参与初始渲染,不触发图片加载、脚本执行、样式计算
-
cloneNode(true)返回的是可多次插入的副本,原content不会被移动或清空 - 必须用
template.content,不是template.innerHTML—— 后者返回空字符串
自定义元素中如何安全注入动态数据
模板本身不支持数据绑定,所有插值必须手动操作 DOM 节点。重点不是“怎么填”,而是“在哪填”和“怎么防错”。
推荐在 connectedCallback 中批量渲染,而非构造函数里 —— 因为此时元素已挂载,可安全访问 shadowRoot 或父容器。若用 Shadow DOM,务必先调用 this.attachShadow({ mode: 'open' })。
- 用
querySelector定位占位节点,比如clone.querySelector('.product-name').textContent = item.name - 对用户输入内容,始终用
textContent而非innerHTML,避免 XSS - 图片
src必须校验协议(如仅允许https:或data:),否则克隆后可能触发非法请求 - 按钮等交互节点,应在克隆后立即绑定事件,不要依赖事件委托(因 Shadow DOM 隔离)
如何避免重复 ID 和样式污染
<template></template> 克隆出的节点默认保留原始 ID,多个实例会导致 ID 冲突(违反 HTML 规范),影响 label[for]、getElementById 等行为。样式若写在 light DOM,也会全局泄漏。
解决方式不是删 ID,而是重写:在克隆后遍历所有带 id 的元素,用 Math.random() 或递增计数器生成唯一值。样式必须进 Shadow DOM,或用 CSS 自定义属性暴露主题点。
- 克隆后执行
clone.querySelectorAll('[id]').forEach(el => el.id += '-'+Date.now())(简单场景) - 更健壮做法:模板中用占位符如
id="item-title-{id}",克隆后用正则替换 - 禁止在模板内写
<style></style>标签并插入 light DOM;应adoptedStyleSheets或shadowRoot.appendChild(style) - 若需复用外部 CSS,用
:host+::slotted控制作用域边界
大规模列表滚动时的性能临界点在哪
即使用了 <template></template> 和自定义元素,一次性渲染 10000 条仍会卡顿 —— 不是模板问题,而是 DOM 节点总量和布局计算压力。此时必须引入虚拟滚动(virtual scrolling),但注意:它和 <template></template> 不冲突,而是叠加策略。
核心原则:只渲染视口内 ±1 屏的内容。自定义元素需暴露 renderItem(item, index) 方法供滚动器调用,并监听 scroll 或使用 IntersectionObserver 触发重绘。
- 不要在自定义元素内部实现完整虚拟滚动逻辑,应专注单个 item 渲染职责
- 用
getBoundingClientRect()判断是否在可视区比scrollTop计算更可靠(尤其有 sticky header 时) - 首次渲染建议限制在 50 条以内,后续按需追加,避免主线程长时间阻塞
- 若用
requestIdleCallback分片渲染,注意 Safari 仍不支持,需降级为setTimeout
appendChild —— 这会导致节点被移动而非复制,第二次渲染时 template.content 已为空。必须确认每次操作都基于 cloneNode(true) 的新鲜副本。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











