react实现循环滚动
实现循环滚动的几种方法
使用CSS动画结合React状态管理
import React, { useState, useEffect } from 'react';
import './ScrollComponent.css';
const ScrollComponent = ({ items }) => {
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex((prevIndex) => (prevIndex + 1) % items.length);
}, 3000);
return () => clearInterval(interval);
}, [items.length]);
return (
<div className="scroll-container">
<div
className="scroll-content"
style={{ transform: `translateY(-${currentIndex * 100}px)` }}
>
{items.map((item, index) => (
<div key={index} className="scroll-item">{item}</div>
))}
{/* 复制第一个元素实现无缝循环 */}
<div className="scroll-item">{items[0]}</div>
</div>
</div>
);
};
CSS样式示例
.scroll-container {
height: 100px;
overflow: hidden;
position: relative;
}
.scroll-content {
transition: transform 0.5s ease-in-out;
}
.scroll-item {
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
使用第三方库react-slick
安装react-slick
npm install react-slick slick-carousel
实现循环滚动组件
import React from 'react';
import Slider from 'react-slick';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
const AutoScrollCarousel = ({ items }) => {
const settings = {
dots: false,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
autoplay: true,
autoplaySpeed: 2000,
vertical: true,
verticalSwiping: true
};
return (
<Slider {...settings}>
{items.map((item, index) => (
<div key={index}>
<h3>{item}</h3>
</div>
))}
</Slider>
);
};
使用requestAnimationFrame实现高性能滚动
import React, { useRef, useEffect } from 'react';
const SmoothScroller = ({ items }) => {
const containerRef = useRef(null);
const contentRef = useRef(null);
const animationRef = useRef(null);
const scrollSpeed = 50; // 像素/秒
useEffect(() => {
let position = 0;
const containerHeight = containerRef.current.clientHeight;
const contentHeight = contentRef.current.clientHeight;
const animate = (timestamp) => {
position += scrollSpeed / 60;
if (position >= contentHeight - containerHeight) {
position = 0;
}
contentRef.current.style.transform = `translateY(-${position}px)`;
animationRef.current = requestAnimationFrame(animate);
};
animationRef.current = requestAnimationFrame(animate);
return () => {
cancelAnimationFrame(animationRef.current);
};
}, []);
return (
<div ref={containerRef} style={{ height: '200px', overflow: 'hidden' }}>
<div ref={contentRef}>
{items.map((item, index) => (
<div key={index} style={{ height: '50px' }}>{item}</div>
))}
{/* 复制内容实现无缝循环 */}
{items.map((item, index) => (
<div key={`copy-${index}`} style={{ height: '50px' }}>{item}</div>
))}
</div>
</div>
);
};
横向循环滚动的实现
const HorizontalScroller = ({ items }) => {
const [scrollPosition, setScrollPosition] = useState(0);
const containerRef = useRef(null);
const contentRef = useRef(null);
useEffect(() => {
const containerWidth = containerRef.current.clientWidth;
const contentWidth = contentRef.current.scrollWidth / 2;
let animationId;
const scroll = () => {
setScrollPosition(prev => {
const newPos = (prev + 1) % contentWidth;
return newPos;
});
animationId = requestAnimationFrame(scroll);
};
animationId = requestAnimationFrame(scroll);
return () => {
cancelAnimationFrame(animationId);
};
}, []);
return (
<div ref={containerRef} style={{ overflow: 'hidden', whiteSpace: 'nowrap' }}>
<div
ref={contentRef}
style={{
display: 'inline-block',
transform: `translateX(-${scrollPosition}px)`
}}
>
{[...items, ...items].map((item, index) => (
<span key={index} style={{ padding: '0 20px' }}>{item}</span>
))}
</div>
</div>
);
};
性能优化建议
-
使用will-change属性优化渲染性能
.scroll-content { will-change: transform; } -
对于大量数据,考虑虚拟滚动技术
-
避免频繁的DOM操作,使用transform代替top/left定位
-
合理设置requestAnimationFrame的调用频率
-
移除不可见的元素时使用CSS opacity而非display:none






