虚拟滚动需结构设计+CSS定位+JS控制,核心是只渲染可视行;必须统一固定行高、三层DOM模拟滚动、节流监听并批量更新tbody内容。

直接用 <table> 标签本身无法实现虚拟滚动——它只是语义容器,不带滚动逻辑。真正起作用的是结构设计 + CSS 定位 + JS 控制渲染范围。核心不是“表格怎么滚”,而是“怎么让浏览器只画当前看得见的几行”。
必须预设固定行高
虚拟滚动依赖精确计算:滚动多少像素对应第几行。如果每行高度不一致,就得反复调用 getBoundingClientRect() 测量,性能直接崩盘。所以第一件事是统一行高:
- 给
<tr>或<td>设固定height: 42px(或类似值),并加box-sizing: border-box - 禁用
white-space: normal导致文字换行撑高;改用white-space: nowrap; overflow: hidden; text-overflow: ellipsis - 图片、图标等内联元素也需约束尺寸,避免意外拉高
用三层 DOM 结构模拟滚动空间
不能把所有 <tr> 都塞进 <tbody>。要拆成三部分:
- 最外层:滚动容器,设
height: 500px; overflow-y: auto - 中间层:占位容器,
position: relative,高度 = 总行数 × 行高(例如height: 100000px) - 最里层:只放当前可视区域的
<tr>,每个用position: absolute+top精确定位(如第 127 行就设top: 127 × 42)
滚动监听要节流且只更新必要内容
原生 scroll 事件每秒触发几十次,直接响应会卡死。正确做法是:
立即学习“前端免费学习笔记(深入)”;
- 用
requestIdleCallback或setTimeout(..., 0)延迟处理,让出主线程 - 每次只算两个值:起始索引
Math.floor(scrollTop / rowHeight)和可视行数Math.ceil(containerHeight / rowHeight) + 4 - 用
slice()截取数据片段,清空旧 DOM 后批量插入新<tr>,别用innerHTML +=
别在 table 内部强行套 virtual-scroll 库
很多 UI 库的虚拟滚动组件默认基于 <div> 渲染,若硬套进 <table> 会破坏 HTML 表格语义和可访问性。更稳妥的方式是:
- 保留
<table>外壳(含<thead>固定表头),但把<tbody>替换为自定义容器 - 表头用
position: sticky; top: 0实现固定,兼容现代浏览器 - 若需 IE11 支持,改用
position: absolute+ 监听scroll手动同步表头位置



















