You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中用react-virtualized实现带箭头水平滚动及触底加载咨询

用react-virtualized实现带箭头的水平滚动+触底加载更多

一、基础水平滚动布局实现

react-virtualized的List组件原生支持水平滚动,配合自定义箭头按钮可实现手动控制滚动的效果。

  1. 安装依赖:
npm install react-virtualized
# 或
yarn add react-virtualized
  1. 核心组件实现(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请求并合并新数据:

  1. 添加状态与加载逻辑:
// 在组件内新增状态
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();
  }
};
  1. 绑定滚动回调到List组件:
<List
  // ...其他原有属性
  onScroll={handleScroll}
/>
  1. 添加加载状态提示:
    在组件底部添加:
{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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 02:33:29