Next.js中用react-virtualized实现带箭头水平滚动及触底加载咨询
用react-virtualized实现带箭头的水平滚动+触底加载更多
一、基础水平滚动布局实现
react-virtualized的List组件原生支持水平滚动,配合自定义箭头按钮可实现手动控制滚动的效果。
- 安装依赖:
npm install react-virtualized # 或 yarn add react-virtualized
- 核心组件实现(Next.js客户端组件):
'use client'; import { useState, useRef } from 'react'; import { List, AutoSizer } from 'react-virtualized'; import 'react-virtualized/styles.css'; // 必须导入默认样式 const HorizontalScrollList = () => { const [data, setData] = useState(Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`)); const listRef = useRef(null); const scrollStep = 300; // 每次点击箭头滚动的固定距离 // 左箭头滚动逻辑 const scrollLeft = () => { if (listRef.current) { const currentScroll = listRef.current.getScrollPosition(); listRef.current.scrollToPosition(Math.max(0, currentScroll - scrollStep)); } }; // 右箭头滚动逻辑 const scrollRight = () => { if (listRef.current) { const currentScroll = listRef.current.getScrollPosition(); listRef.current.scrollToPosition(currentScroll + scrollStep); } }; // 渲染列表项 const renderRow = ({ index, key, style }) => ( <div key={key} style={{ ...style, width: 250, height: 150, border: '1px solid #eee', display: 'flex', alignItems: 'center', justifyContent: 'center' }} > {data[index]} </div> ); return ( <div style={{ position: 'relative', width: '100%', height: 180 }}> {/* 左箭头按钮 */} <button onClick={scrollLeft} style={{ position: 'absolute', left: 10, top: '50%', transform: 'translateY(-50%)', zIndex: 10, padding: '8px 12px', cursor: 'pointer' }}> ← </button> {/* 右箭头按钮 */} <button onClick={scrollRight} style={{ position: 'absolute', right: 10, top: '50%', transform: 'translateY(-50%)', zIndex: 10, padding: '8px 12px', cursor: 'pointer' }}> → </button> {/* AutoSizer自动适配容器尺寸 */} <AutoSizer> {({ width, height }) => ( <List ref={listRef} width={width} height={height} rowCount={data.length} rowWidth={250} rowHeight={150} scrollDirection="horizontal" rowRenderer={renderRow} /> )} </AutoSizer> </div> ); }; export default HorizontalScrollList;
二、滚动至末尾的回调(触底加载更多)
通过List组件的onScroll回调,计算滚动位置判断是否到达列表末尾,触发API请求并合并新数据:
- 添加状态与加载逻辑:
// 在组件内新增状态 const [loading, setLoading] = useState(false); const [hasMore, setHasMore] = useState(true); // 模拟API请求,替换为你的真实接口调用 const fetchMoreData = async () => { setLoading(true); const newData = await new Promise(resolve => { setTimeout(() => { resolve(Array.from({ length: 10 }, (_, i) => `Item ${data.length + i + 1}`)); }, 1000); }); // 合并新数据到现有列表 setData(prev => [...prev, ...newData]); setLoading(false); // 示例:最多加载50条数据后停止 if (data.length + newData.length >= 50) { setHasMore(false); } }; // 滚动回调:判断是否到达末尾 const handleScroll = ({ scrollLeft, clientWidth, scrollWidth }) => { const threshold = 50; // 距离末尾50px时触发加载 if (scrollLeft + clientWidth >= scrollWidth - threshold && !loading && hasMore) { fetchMoreData(); } };
- 绑定滚动回调到
List组件:
<List // ...其他原有属性 onScroll={handleScroll} />
- 添加加载状态提示:
在组件底部添加:
{loading && <div style={{ textAlign: 'center', marginTop: 10 }}>加载中...</div>} {!loading && !hasMore && <div style={{ textAlign: 'center', marginTop: 10 }}>没有更多数据了</div>}
三、关键注意事项
- 必须导入
react-virtualized/styles.css,否则列表布局会异常。 - 使用
AutoSizer确保List能正确获取容器尺寸,避免滚动失效。 - 触底判断时加入
loading和hasMore状态,防止重复请求和无效调用。 - Next.js中需添加
'use client'指令,因为涉及客户端交互与状态管理。
内容的提问来源于stack exchange,提问作者Vishwa
相关产品推荐
相关产品推荐

