js
import './index.less';
import { useEffect, useState } from 'react';
import CountUp from 'react-countup';
import { autoplaySpeed } from '@/global';
//此数据关联滚动次数刷新机制
const numArr = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9,
];
interface Props {
num: string | number; // '123' | 123
refreshTime?: number; // 刷新时间 默认10秒
}
const Digit = (props: Props) => {
// 定时器
let intervalId: any = null;
let updateTimes = 0; // 刷新次数 超过五次还原初始位置
const { num, refreshTime } = props; //传入的数字和刷新时间
const [digits, setDigits] = useState(numArr); // 滚动的数字数组
const [numberStr, setNumberStr] = useState(); // 传入的数字
const [refArr, setRefArr] = useState([]); // 滚动的dom数组
const [firstPointArr, setFirstPointArr] = useState([]); // 第一次的位置数据
const [countState, setCountState] = useState(0); // 0 countUp 1 数字滚动刷新
//判断num是否为数字
function isNumber(num: any) {
return (
(typeof num === 'number' || typeof Number(num) === 'number') &&
!isNaN(num)
);
}
//开启定时任务
function startIntervalTask() {
if (!intervalId && isNumber(num)) {
const intervalId = setInterval(
() => {
//记录刷新次数
updateTimes++;
refArr.forEach((el, index) => {
if (el) {
//获取translate 值
let translateY = el.style.transform.split(',')[1]?.split(')')[0];
//去掉px
translateY = Number(translateY?.slice(0, -2));
el.style.transform = `translate(-50%,${translateY - 320}px)`;
}
});
// 刷新次数超过5次 还原位置
if (updateTimes > 5) {
updateTimes = 0;
refArr.forEach((el, index) => {
if (el) {
el.style.transform = `translate(-50%,${firstPointArr[index]}px)`;
}
});
return;
}
},
refreshTime ? refreshTime : autoplaySpeed,
);
return intervalId;
} else {
//console.log("服务已经启动")
}
}
// 监听num变化
useEffect(() => {
if (isNumber(num)) {
setCountState(0); //num变化 改为countUp组件重新初始化
setNumberStr(num);
setRefArr(new Array(num?.toString().length).fill(null));
}
}, [num]);
useEffect(() => {
setTimeout(() => {
//2秒后改为自动轮播逻辑
if (countState == 0) {
setCountState(1);
}
}, 2000);
}, [refArr]);
//监听countState变化
useEffect(() => {
if (countState == 1) {
//记录第一次的位置数据
const pointArr: any = [];
refArr.forEach((el, index) => {
if (el) {
//获取translate值
let translateY = el.style.transform.split(',')[1]?.split(')')[0];
//去掉px
translateY = Number(translateY?.slice(0, -2));
pointArr.push(translateY);
}
});
setFirstPointArr(pointArr);
}
}, [countState]);
//监听pointArr 开启定时任务
useEffect(() => {
let id: any = null;
if (firstPointArr.length > 0) {
id = startIntervalTask();
}
return () => {
clearInterval(id);
id = null;
};
}, [firstPointArr]);
return (
<div className="numberDsiplay">
{numberStr
?.toString()
.split('')
.map((digitStr, index) =>
countState == 0 ? (
<div
className="digitWrapper"
key={'CountUp-' + digitStr + '-' + index}
>
<CountUp
start={0}
separator=""
duration={2}
end={Number(digitStr)}
/>
</div>
) : (
<div
className="digitWrapper"
key={'digit-' + digitStr + '-' + index}
>
<span
className="digitList"
ref={(el) => {
refArr[index] = el;
setRefArr(refArr);
}}
style={{
transform: `translate(-50%,${-Number(digitStr) * 32}px)`,
transitionDelay: `${index * 100}ms`,
}}
>
{digits.map((digit, index) => (
<span
className="digit"
key={
'digit-' +
digit +
'-' +
index +
'-' +
(digitStr + '-' + index)
}
>
{digit}
</span>
))}
</span>
</div>
),
)}
</div>
);
};
export default Digit;
css
.numberDsiplay {
display: flex;
align-items: center;
justify-content: center;
// padding: 5px 0;
.digitWrapper {
width: 24px;
text-align: center;
height: 32px;
font-size: 24px;
line-height: 32px;
// background-color: black;
border: 1px transparent solid;
border-image: linear-gradient(to bottom, #00ffff, #29292c) 2 10;
position: relative;
// border-radius: 6px;
// margin-right: 0;
overflow: hidden;
span {
color: #f0ff00 !important;
}
&:last-child {
margin-right: 5px;
}
}
.digitList {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
color: #f0ff00 !important;
display: flex;
flex-direction: column;
align-items: center;
transition: transform 600ms;
}
}
效果
定时滚动