前言
你是否只会使用element、antd等组件库的表格?你是否只会谴责后端返回的数据很多,导致你的页面卡爆,卡成ppt,用户体验下降?你是否会因为数据量太大,导致页面卡顿,用户体验下降?虚拟列表,你是不是经常听到定高的列表,不定高的虚拟列表,这是不是听起来很懵逼,那么你是不是以为我会讲虚拟列表?
不,我今天不讲虚拟列表,今天我来讲canvas实现一个高性能的table,再也不担心后端返回大量数据,导致前端的页面卡顿,用户体验下降。
依旧是我们的Trae ai,先简单的提问,让Trae模拟大量的数据,这样就不用我们手动添加了,偷个懒吧,啊哈哈哈

看看最终的样式效果,滚动起来,一点都不卡顿,很丝滑

Trae的实现思路
一、Trae设计的思路
- 目标:在普通浏览器环境中流畅渲染 10 万+ 行表格,滚动不卡顿。
- 核心策略:Canvas 即时渲染 + 虚拟滚动。只绘制"可视区域内"的行,不创建海量 DOM 节点。
- 关键优化:
- 高 DPI 适配:一次性 setTransform(dpr, 0, 0, dpr, 0, 0) 消除模糊。
- 预计算列几何:列累计偏移 colX[] 只算一次,循环直接查表。
- requestAnimationFrame 合帧:滚动时只在下一帧绘制,避免重复触发。
- 数据"按需生成":通过行号生成数据,不在内存里存放 10 万对象。
二、数据与内存策略
- 不真正"持有"数据数组,而是利用行号 i 通过一个轻量的伪随机函数生成可复现的数据。这样总内存占用基本与总行数无关,只有可见行的文本参与绘制。
- 优点:零初始化成本、零大对象分配、滚动时无需数据搬运。
Trae的实现代码
预计算列位置,避免重复相加成本
js
const colX = new Array(COLS.length + 1);
function computeColX() {
colX[0] = 0;
for (let i = 0; i < COLS.length; i++) colX[i + 1] = colX[i] + COLS[i];
}
computeColX();
用行号 i 生成稳定的"随机"数据,避免存储大数组
js
function rand(i){ const x = Math.sin(i * 9999) * 10000; return x - Math.floor(x); }
function rowData(i){
const n = i + 1;
const age = 18 + Math.floor(rand(n)*40);
const score = (rand(n*3)*100).toFixed(2);
const level = ['Bronze','Silver','Gold','Platinum','Diamond'][Math.floor(rand(n*7)*5)];
const status = rand(n*11) > 0.5 ? '正常' : '冻结';
const city = ['上海','北京','深圳','杭州','成都','武汉','西安','广州'][Math.floor(rand(n*5)*8)];
const time = new Date(1600000000000 + Math.floor(rand(n*13)*1e10)).toISOString().slice(0,19).replace('T',' ');
return [n, '用户'+n, city, age, score, level, status, time, 'OD'+(100000+n), '---'];
}
关键的虚拟滚动实现
js
const firstRow = Math.max(0, Math.floor((viewTop - HEADER_H) / ROW_H));
const visibleCount = Math.ceil(h / ROW_H) + 1;
const lastRow = Math.min(TOTAL_ROWS, firstRow + visibleCount);
let y = HEADER_H - ((viewTop - HEADER_H) % ROW_H);
高 DPI 渲染适配
js
const dpr = Math.max(1, Math.floor(window.devicePixelRatio || 1));
canvas.width = w * dpr; canvas.height = h * dpr;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0); // 只设置一次
总结
虚拟滚动是一种优化长列表渲染的技术,通过只渲染可视区域内的元素,大幅减少 DOM 操作和重绘,提高性能。
本文介绍了canvas表格虚拟滚动的原理和实现,包括如何计算可视区域、如何渲染数据、如何处理滚动事件等。通过虚拟滚动,我们可以轻松处理百万级的数据,实现流畅的滚动效果。
如果你之前没有接触过虚拟滚动,希望本文能帮你入门。如果你已经熟悉虚拟滚动,希望本文能帮你优化你的实现。