你这几点基本把固定行高方案从「能跑」补到「敢上线」了,我只在 overscan 的方向性、scrollToIndex 的实现差异和图片撑高这三处补几个实操细节。
overscan 建议按滚动方向做不对称。 对称的 5+5 行在往下滑时,前面 5 行是纯粹的浪费。记一个 lastScrollTop,向下滚时前方给 6~8 行、后方只留 1~2 行,反向再翻转,节点数差不多但抗白屏能力明显更好。另外 buffer 值不该是常量:行内有图片或图表时,多渲染一行就多一次解码,这时宁可 buffer 取小、靠 will-change: transform 只在实际滚动期间加(滚动停止后移除,别常驻,否则合成层常驻吃显存)。
scrollToIndex 在固定行高的场景不用「先渲染再测量」——直接 viewport.scrollTop = index * rowH 一行就到位,测量那套是动态高度才需要的。建议顺手加个对齐参数(start / center / end),锚点跳转时体验差别很大。还有 iOS 惯性回弹会让 scrollTop 短暂为负值,记得 clamp 到 [0, totalH - viewH],不然 startIndex 算出负数直接取不到数据。
图片撑高是最容易被忽略的固定行高杀手。 行内 <img> 不设尺寸,加载完成后行高被顶开,scrollTop / rowH 的换算立刻失真、整段错位。给所有行内媒体锁死高度 + object-fit: cover,或者直接用 aspect-ratio 占位。
最后一个小建议:真要处理百万级,content-visibility: auto + contain-intrinsic-size 值得放进备选方案,简单列表甚至能不写 JS;但它不减 DOM 数量,十万条还是老老实实上虚拟列表。

钻石卡会员
正式会员
认证极客









