虚拟滚动时为什么还是会有重复渲染和卡顿?
我在用虚拟滚动渲染长列表时,虽然实现了可视区域截取,但滚动到列表中段时偶尔会出现重复渲染的列表项,甚至卡顿一下。尝试用IntersectionObserver监听可视区域,但发现当快速滚动时计算的startIndex和endIndex会有偏差。
代码大概是这样写的:
const observer = new IntersectionObserver(entries => {
const rect = entries[0].boundingClientRect;
const start = Math.floor(rect.top / itemHeight);
const end = Math.ceil((rect.bottom + window.innerHeight) / itemHeight);
setRenderRange({ start, end }); // 这里可能有问题?
});
observer.observe(ref.current);
但发现当列表项高度不固定时,计算出来的范围会错位,导致渲染区域重叠。有没有更好的可视区域计算方式?
代码可以改成这样:
记得用一个预估的
estimatedItemHeight来处理高度不固定的场景,避免计算偏差。如果高度差异太大,可以在数据里加一个缓存记录每个项的真实高度,动态调整计算结果。别忘了在组件销毁时清理监听器。IntersectionObserver不是最佳选择,尤其当列表项高度动态变化时,计算会越来越不准。试试下面这种基于滚动容器的方案,直接监听滚动事件来动态调整渲染范围。);
}
// 使用示例
function App() {
const itemCount = 1000;
const itemHeights = Array.from({ length: itemCount }, () => Math.floor(Math.random() * 50 + 50));
const getItemHeight = (index) => itemHeights[index];
const renderItem = (index) =>
Item ${index};return
}
这个代码解决了两个核心问题:一是支持动态高度,通过累加计算每个元素的位置;二是优化了快速滚动时的偏差,增加了一个缓冲区(
startIndex - 5和endIndex + 5)。复制过去试试,应该能解决你的重复渲染和卡顿问题。如果还有问题再交流。