如何滚动到react-virtualized渲染的指定React元素
解决react-virtualized虚拟列表滚动到指定未渲染项的方案
问题核心原因
- 虚拟滚动的核心逻辑是仅渲染视口及周边少量列表项,未进入渲染范围的项不存在真实DOM节点,你给每个列表项绑定ref的方案自然拿不到未渲染项的DOM,调用
getBoundingClientRect就会抛出空值错误。 - 不需要手动通过DOM计算位置,react-virtualized的
List组件本身暴露了跳转指定行的官方API,直接调用即可。
具体改造步骤
- 给
List组件创建实例ref,不需要给每个列表项单独绑定ref - 点击跳转按钮时,拿到目标项的索引,调用
List实例的scrollToRow方法即可自动滚动到对应位置,组件内部会自动计算目标项的偏移量,哪怕该项未提前渲染也可以正常跳转。
改造后代码示例
import { useRef } from 'react'; import { WindowScroller, AutoSizer, List } from 'react-virtualized'; // 你自己定义的arr数据源 const arr = Array.from({length: 100}, (_, i) => ({id: i+1})); export default function App() { // 给List组件创建ref const listRef = useRef(null); const onClick = (targetIndex) => { // 直接调用List实例的scrollToRow方法跳转到对应索引的项 listRef.current?.scrollToRow(targetIndex); // 如果需要平滑滚动,且你的行高是固定值100,可以直接计算偏移量用原生滚动: // window.scrollTo({ // top: targetIndex * 100, // behavior: 'smooth' // }) }; const items = arr.map((el) => ({ id: el.id })); return ( <div className="App"> {items.map((item, index) => ( <button onClick={() => onClick(index)} key={item.id}>Scroll to {item.id}</button> ))} <WindowScroller> {({ height, scrollTop, registerChild }) => ( <div ref={registerChild}> <AutoSizer disableHeight> {({ width }) => ( <List ref={listRef} // 绑定ref到List组件 autoHeight width={width} height={height} rowHeight={100} rowRenderer={({ index }) => { return ( <div id={`item-${items[index].id}`} key={items[index].id} style={{height: 100, border: '1px solid #eee'}} > {items[index].id} </div> ); }} scrollTop={scrollTop} rowCount={items.length} overscanRowCount={10} // 不需要设置过大的overscan,浪费性能 // 如果需要调整跳转后目标项的对齐方式,可以加scrollToAlignment参数,可选值为"start"/"center"/"end"/"auto" scrollToAlignment="start" /> )} </AutoSizer> </div> )} </WindowScroller> </div> ); }
补充说明
- 如果你的行高是动态计算的,只要给
List正确传入rowHeight的计算函数,scrollToRow依然可以正常工作,不需要手动处理偏移。 scrollToAlignment参数可以控制跳转后目标项在视口的对齐位置:start为顶部对齐,center为居中,end为底部对齐,auto为自动滚动到最近的位置。- 要平滑滚动效果的话,因为react-virtualized原生
scrollToRow不支持smooth行为,固定行高场景直接按行高乘索引算偏移量调用原生window.scrollTo即可,动态行高场景可以自己通过List实例的getOffsetForRow方法获取目标偏移量再调用原生滚动。
内容的提问来源于stack exchange,提问作者Stretch0
相关产品推荐
相关产品推荐

