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

React实现无回滚无限轮播组件(不依赖第三方库)

React无回滚无限轮播组件实现(无第三方库)

核心思路

要实现无回滚的无缝轮播,核心是视觉欺骗+DOM重置:

  • 给原始轮播列表首尾各复制一份对方的元素(比如原列表[1,2,3,4]处理为[4,1,2,3,4,1])
  • 正常滚动时用CSS过渡实现平滑滑动;当滚动到复制的边界元素时,瞬间重置到真实列表的对应位置(同时关闭过渡动画),用户完全感知不到跳变

完整代码实现

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

const InfiniteCarousel = ({ items }) => {
  // 处理后的轮播列表:首尾各加一份对方的元素
  const carouselItems = [items[items.length - 1], ...items, items[0]];
  const [currentIndex, setCurrentIndex] = useState(1); // 初始从真实列表第一个元素开始
  const containerRef = useRef(null);
  const itemRef = useRef(null);
  let itemWidth = 0;

  // 获取单个轮播项的宽度
  useEffect(() => {
    if (itemRef.current) {
      itemWidth = itemRef.current.offsetWidth;
    }
  }, []);

  // 处理过渡结束后的索引重置
  const handleTransitionEnd = () => {
    if (currentIndex === 0) {
      // 滚动到开头的复制元素,重置到真实列表最后一个
      setCurrentIndex(items.length);
      // 关闭过渡,瞬间跳转
      containerRef.current.style.transition = 'none';
      containerRef.current.style.transform = `translateX(-${items.length * itemWidth}px)`;
      // 在下一帧重新开启过渡
      requestAnimationFrame(() => {
        containerRef.current.style.transition = 'transform 0.5s ease';
      });
    } else if (currentIndex === carouselItems.length - 1) {
      // 滚动到结尾的复制元素,重置到真实列表第一个
      setCurrentIndex(1);
      containerRef.current.style.transition = 'none';
      containerRef.current.style.transform = `translateX(-${1 * itemWidth}px)`;
      requestAnimationFrame(() => {
        containerRef.current.style.transition = 'transform 0.5s ease';
      });
    }
  };

  // 向右切换
  const handleNext = () => {
    setCurrentIndex(prev => prev + 1);
  };

  // 向左切换
  const handlePrev = () => {
    setCurrentIndex(prev => prev - 1);
  };

  return (
    <div style={{ width: '600px', margin: '0 auto', overflow: 'hidden', position: 'relative' }}>
      <div
        ref={containerRef}
        style={{
          display: 'flex',
          transform: `translateX(-${currentIndex * itemWidth}px)`,
          transition: 'transform 0.5s ease',
        }}
        onTransitionEnd={handleTransitionEnd}
      >
        {carouselItems.map((item, idx) => (
          <div
            key={idx}
            ref={idx === 1 ? itemRef : null}
            style={{
              width: '600px',
              height: '200px',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              fontSize: '48px',
              backgroundColor: idx % 2 === 0 ? '#f0f0f0' : '#e0e0e0',
            }}
          >
            {item}
          </div>
        ))}
      </div>
      {/* 切换按钮 */}
      <button
        onClick={handlePrev}
        style={{ position: 'absolute', left: '10px', top: '50%', transform: 'translateY(-50%)', padding: '8px 16px', cursor: 'pointer' }}
      >
        ←
      </button>
      <button
        onClick={handleNext}
        style={{ position: 'absolute', right: '10px', top: '50%', transform: 'translateY(-50%)', padding: '8px 16px', cursor: 'pointer' }}
      >
        →
      </button>
    </div>
  );
};

// 使用示例
const App = () => {
  const items = [1, 2, 3, 4];
  return (
    <div style={{ padding: '50px 0' }}>
      <InfiniteCarousel items={items} />
    </div>
  );
};

export default App;

效果说明

  • 向右滚动到4后,会平滑过渡到1,无任何回滚跳变;向左滚动到1后,平滑过渡到4
  • 所有动画通过原生CSS transition 实现,没有依赖任何第三方库

效果示例图

![无回滚无限轮播效果示例](https://via.placeholder.com/600x250?text=无缝轮播演示:4→1→2→3→4... 无回滚跳变)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 10:02:22