核心是减少每帧DOM操作、避免重排重绘、控制主线程负载;精简DOM结构、禁用冗余容器、用虚拟滚动和原生DOM批量写入,可使10,000行表格渲染从2.3秒降至45ms。

核心是减少每帧内 DOM 操作量、避免重排重绘、控制主线程负载。帧率下降往往不是数据多,而是浏览器在单帧里被迫处理成千上万个节点或反复计算样式。
精简 DOM 结构,直接砍掉冗余节点
主流 UI 库(如 Element Plus、Ant Design)默认生成多层包裹结构:<div class="table-wrapper"><div class="body-wrapper"><table><tbody><tr><td>…</td></tr></tbody></table></div></div>。这些 wrapper 多数只用于样式隔离或滚动控制,对渲染无实质作用。
- 禁用非必要容器:比如不需要表头时设
:show-header="false",可减少约 15% 的 DOM 节点 - 单元格内不用嵌套
<div><span><i></i></span></div>包裹文字,改用纯文本 + CSS 控制换行、对齐、图标(如伪元素::before插入 icon) - 慎用插槽渲染重型组件(如
<el-select>),每个实例都带独立响应式系统和事件监听器,DOM 膨胀呈倍数增长
只渲染可视区域,用虚拟滚动替代全量挂载
10,000 行表格若全量渲染,哪怕每行仅 8 列,也会产生近 8 万个 <td> 节点,浏览器重排压力极大。虚拟滚动让实际 DOM 节点数稳定在 20–50 个左右。
- 固定行高(如 44px)便于快速计算可视起始索引:
startIdx = Math.floor(scrollTop / rowHeight) - 用
document.createDocumentFragment()批量插入当前可见行,再一次性appendChild到<tbody>,避免逐行触发重排 - 内容容器需设
position: absolute+top定位,配合总高度撑开滚动空间(style.height = data.length * rowHeight + "px")
分片渲染 + requestAnimationFrame 控制节奏
即使启用虚拟滚动,首次加载或筛选后重绘仍可能卡顿。把“生成并插入 DOM”这个动作切分成小块,交由浏览器按帧调度。
立即学习“Java免费学习笔记(深入)”;
- 每帧只处理 20–30 行:用
requestAnimationFrame触发下一批,确保不阻塞用户交互 - 避免
setTimeout(fn, 0)—— 它是宏任务,可能被其他异步任务挤占;requestAnimationFrame严格对齐屏幕刷新(60fps ≈ 16.6ms/帧) - 结合
IntersectionObserver对横向懒加载列做触发:当某列进入可视区域时,才动态插入该列的<th>和所有<td>
绕过响应式系统,用原生 DOM 批量写入
Vue/React 组件封装带来便利,也引入额外开销。当表格以展示为主(无复杂编辑、校验、联动),直接操作原生 DOM 效率更高。
- 预先计算好 HTML 字符串,用
tbody.innerHTML = htmlString一次性写入(比循环createElement快 3–5 倍) - 数据对象保持普通 JS 对象(非
ref或reactive),避免响应式追踪开销 - 实测对比:10,000×8 数据,原生拼接耗时约 45ms;Element Plus 全量渲染超 2.3s,且滚动明显掉帧



















