react开发的一个左右无缝滚动列表跑马灯抽奖 开始是匀速左右滚动 点击开始抽奖按钮 滚动速度在60s内先加快 然后速度慢慢变为0 停止滚动 然后中奖列表元素处理滚动列表左右的中间高亮显示
时间: 2025-09-10 18:09:36 AIGC 浏览: 5
以下是实现 React 左右无缝滚动列表跑马灯抽奖的代码,满足列表开始时匀速左右滚动,点击开始抽奖按钮后,滚动速度在 60 秒内先加快然后慢慢降为 0 停止滚动,最后将中奖列表元素在滚动列表左右中间高亮显示的需求:
```jsx
import React, { useState, useEffect, useRef } from 'react';
import './App.css';
const prizes = [
'奖品1',
'奖品2',
'奖品3',
'奖品4',
'奖品5',
'奖品6',
];
function App() {
const [isRunning, setIsRunning] = useState(false);
const [winner, setWinner] = useState('');
const [speed, setSpeed] = useState(10); // 初始速度
const [timeLeft, setTimeLeft] = useState(60);
const marqueeRef = useRef(null);
const animationFrameRef = useRef(null);
const positionRef = useRef(0);
const startLottery = () => {
setIsRunning(true);
setSpeed(30); // 加速
const startTime = Date.now();
const intervalId = setInterval(() => {
const elapsedTime = (Date.now() - startTime) / 1000;
setTimeLeft(60 - elapsedTime);
if (elapsedTime >= 60) {
clearInterval(intervalId);
// 停止滚动
setIsRunning(false);
const randomIndex = Math.floor(Math.random() * prizes.length);
setWinner(prizes[randomIndex]);
cancelAnimationFrame(animationFrameRef.current);
// 调整位置使中奖元素在中间
const itemWidth = 200;
const centerOffset = -((randomIndex * itemWidth) - (marqueeRef.current.offsetWidth / 2 - itemWidth / 2));
positionRef.current = centerOffset;
marqueeRef.current.style.transform = `translateX(${centerOffset}px)`;
} else if (elapsedTime > 30) {
// 30 秒后开始减速
const deceleratedSpeed = 30 - ((elapsedTime - 30) * (30 / 30));
setSpeed(deceleratedSpeed);
}
}, 100);
};
useEffect(() => {
const animate = () => {
if (isRunning) {
positionRef.current -= speed;
if (positionRef.current < -prizes.length * 200) {
positionRef.current = 0;
}
marqueeRef.current.style.transform = `translateX(${positionRef.current}px)`;
animationFrameRef.current = requestAnimationFrame(animate);
}
};
if (isRunning) {
animationFrameRef.current = requestAnimationFrame(animate);
} else {
cancelAnimationFrame(animationFrameRef.current);
}
return () => cancelAnimationFrame(animationFrameRef.current);
}, [isRunning, speed]);
return (
<div className="App">
<div className="marquee-container" ref={marqueeRef}>
{prizes.map((prize, index) => (
<div
key={index}
className={`prize-item ${winner === prize ? 'highlight' : ''}`}
>
{prize}
</div>
))}
</div>
<button className="start-button" onClick={startLottery}>
开始抽奖
</button>
{winner && <p className="winner-text">恭喜获得:{winner}</p>}
{isRunning && <p>剩余时间:{Math.max(0, Math.floor(timeLeft))} 秒</p>}
</div>
);
}
export default App;
```
### CSS 样式
```css
.App {
text-align: center;
padding: 50px;
}
.marquee-container {
display: flex;
overflow: hidden;
width: 100%;
height: 100px;
border: 1px solid #ccc;
}
.prize-item {
flex-shrink: 0;
width: 200px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
}
.highlight {
background-color: yellow;
}
.start-button {
margin-top: 20px;
padding: 10px 20px;
font-size: 18px;
cursor: pointer;
}
.winner-text {
margin-top: 20px;
font-size: 24px;
color: red;
}
```
### 代码解释
- **状态管理**:`isRunning` 控制滚动状态,`winner` 存储中奖结果,`speed` 控制滚动速度,`timeLeft` 记录剩余时间。
- **动画控制**:使用 `requestAnimationFrame` 实现滚动动画,点击开始抽奖按钮后,速度在 30 秒内加速,后 30 秒减速,60 秒后停止。
- **中奖定位**:抽奖结束后,计算中奖元素的位置并将其调整到列表中间,同时添加高亮样式。
阅读全文