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

如何在ReactJS项目中实现水平无限滚动?

React 水平无限滚动实现方案

一、原生滚动监听实现(无额外依赖)

直接监听滚动容器的scroll事件,判断滚动位置是否接近右侧边缘,触发加载逻辑,适合简单场景。

实现代码

import { useEffect, useState, useRef } from 'react';

const HorizontalInfiniteScroll = () => {
  // 初始化列表数据
  const [items, setItems] = useState(Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`));
  const [isLoading, setIsLoading] = useState(false);
  const scrollContainerRef = useRef(null);

  // 模拟异步加载数据
  const fetchMore = async () => {
    setIsLoading(true);
    // 模拟接口请求延迟
    await new Promise(resolve => setTimeout(resolve, 1000));
    const newItems = Array.from({ length: 10 }, (_, i) => `Item ${items.length + i + 1}`);
    setItems(prev => [...prev, ...newItems]);
    setIsLoading(false);
  };

  // 监听滚动事件
  useEffect(() => {
    const handleScroll = () => {
      const container = scrollContainerRef.current;
      if (!container) return;

      const { scrollLeft, clientWidth, scrollWidth } = container;
      // 距离右侧边缘100px时触发加载(可自定义阈值)
      if (scrollWidth - scrollLeft - clientWidth < 100 && !isLoading) {
        fetchMore();
      }
    };

    const container = scrollContainerRef.current;
    container?.addEventListener('scroll', handleScroll);
    // 组件卸载时移除监听
    return () => container?.removeEventListener('scroll', handleScroll);
  }, [isLoading, items.length]);

  return (
    <div 
      ref={scrollContainerRef}
      style={{
        width: '100%',
        overflowX: 'auto',
        padding: '1rem 0',
      }}
    >
      <div 
        style={{
          display: 'flex',
          gap: '1rem',
          paddingRight: '1rem', // 避免最后一项被滚动条遮挡
        }}
      >
        {items.map((item, idx) => (
          <div
            key={idx}
            style={{
              minWidth: '200px',
              height: '150px',
              backgroundColor: '#f0f0f0',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              borderRadius: '8px',
            }}
          >
            {item}
          </div>
        ))}
        {/* 加载状态提示 */}
        {isLoading && (
          <div
            style={{
              minWidth: '200px',
              height: '150px',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
            }}
          >
            加载中...
          </div>
        )}
      </div>
    </div>
  );
};

export default HorizontalInfiniteScroll;

关键参数说明

  • scrollLeft:容器已滚动的水平距离
  • clientWidth:容器的可视宽度
  • scrollWidth:容器内所有内容的总宽度
  • 阈值设为100px是为了提前触发加载,避免用户等待,可根据需求调整

二、虚拟滚动实现(大数据量场景)

如果列表项数量很多,原生渲染会有性能问题,推荐用react-window实现虚拟滚动,只渲染可视区域内的项,同时支持水平无限加载。

步骤1:安装依赖

npm install react-window

实现代码

import { useState, useEffect } from 'react';
import { FixedSizeList as List } from 'react-window';

const HorizontalVirtualInfinite = () => {
  const [items, setItems] = useState(Array.from({ length: 50 }, (_, i) => `Item ${i + 1}`));
  const [isLoading, setIsLoading] = useState(false);

  const fetchMore = async () => {
    setIsLoading(true);
    await new Promise(resolve => setTimeout(resolve, 1000));
    const newItems = Array.from({ length: 20 }, (_, i) => `Item ${items.length + i + 1}`);
    setItems(prev => [...prev, ...newItems]);
    setIsLoading(false);
  };

  // 监听滚动触发加载
  useEffect(() => {
    const handleScroll = ({ target }) => {
      const { scrollLeft, clientWidth, scrollWidth } = target;
      if (scrollWidth - scrollLeft - clientWidth < 150 && !isLoading) {
        fetchMore();
      }
    };

    const container = document.querySelector('.horizontal-virtual-container');
    container?.addEventListener('scroll', handleScroll);
    return () => container?.removeEventListener('scroll', handleScroll);
  }, [isLoading, items.length]);

  // 渲染单个列表项
  const renderItem = ({ index, style }) => {
    // 加载状态项
    if (index === items.length && isLoading) {
      return (
        <div
          style={{
            ...style,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          加载中...
        </div>
      );
    }
    return (
      <div
        style={{
          ...style,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: '#f0f0f0',
          marginRight: '1rem',
          borderRadius: '8px',
        }}
      >
        {items[index]}
      </div>
    );
  };

  return (
    <div className="horizontal-virtual-container" style={{ width: '100%', overflowX: 'auto' }}>
      <List
        horizontal
        height={150}
        itemCount={items.length + (isLoading ? 1 : 0)}
        itemSize={210} // 项宽度+右侧margin的总宽度
        width={'100%'}
      >
        {renderItem}
      </List>
    </div>
  );
};

export default HorizontalVirtualInfinite;

优势

  • 虚拟滚动大幅减少DOM节点数量,提升性能
  • 支持水平方向配置,适合大数据量的水平列表场景

三、替代库推荐

如果不想自己写监听逻辑,可以试试这些支持水平滚动的库:

  • react-infinite-scroll-hook:自定义Hook,支持监听水平滚动事件
  • react-scroll-trigger:可灵活监听滚动位置,触发加载逻辑

内容的提问来源于stack exchange,提问作者himanshu_942

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 02:05:41