虚拟列表滚动时为什么会出现白屏闪烁?

利云的笔记 阅读 60

我在用 React 实现虚拟列表时,快速滚动经常看到白屏一闪,体验很糟糕。明明已经按可视区域渲染了,数据量也不大(大概 1000 条)。

我试过用 React.memo 包裹子项,也加了 key,但问题还在。是不是我的高度计算有问题?

const getItemHeight = (index) => {
  return 60; // 所有项高度固定
};
const visibleCount = Math.ceil(containerHeight / itemHeight);
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = startIndex + visibleCount;
我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
❤梓熙
❤梓熙 Lv1
你遇到的白屏闪烁问题很可能跟列表项的渲染时机有关。虽然你的高度计算看起来没问题,但可以试试这样优化一下。

首先建议在获取 startIndex 和 endIndex 时加上一个缓冲区,比如多渲染几个元素:

const buffer = 3;
const visibleCount = Math.ceil(containerHeight / itemHeight) + buffer * 2;
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);
const endIndex = startIndex + visibleCount;


这样做可以让滚动时有更多预渲染的内容,减少空白出现的机会。

另外记得检查 scrollTop 的获取方式,最好用 requestAnimationFrame 包裹你的滚动事件处理逻辑:

let ticking = false;
container.addEventListener('scroll', function() {
if (!ticking) {
requestAnimationFrame(() => {
scrollTop = container.scrollTop;
// 更新列表逻辑
ticking = false;
});
ticking = true;
}
});


我之前也踩过类似的坑,特别是快速滚动时的性能优化真是个头疼的问题,希望能帮到你。
点赞
2026-04-01 02:05
端木树萱
这种白屏闪烁大概率是因为你只渲染了刚刚好塞满可视区域的节点,没有任何富余。快速滚动的时候,浏览器滚动的速度往往快于 React 渲染新节点的速度,导致旧节点销毁了,新节点还没挂载出来,中间露出的就是容器底色。

一般这样处理,加个缓冲区。在可视区域的上方和下方额外多渲染几条数据,比如多渲染半个屏幕的高度或者固定的 5 到 10 条。这样当你滚动时,下一屏的内容其实已经在 DOM 树里准备好了,肉眼就看不出闪烁。

代码上主要改一下 startIndex 和 endIndex 的计算逻辑,引入一个 bufferCount:

const bufferCount = 5; // 缓冲区数量,根据实际情况调整
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - bufferCount);
const endIndex = Math.min(data.length, Math.floor(scrollTop / itemHeight) + visibleCount + bufferCount);


另外要注意,你的容器高度必须是固定的,且父容器要有 overflow: auto 或 scroll,不然计算会乱。如果加了 buffer 还是不行,检查一下是不是 itemHeight 和实际渲染的高度对不上,哪怕差 1 像素,滚久了也会累积出白屏。
点赞 3
2026-03-04 13:55