react + ant-design实现数字对比动画效果:当新获取的数字比之前展示的数字多或少2时,显示“+2”或“-2”的动画效果
react + ant-design实现数字对比动画效果:当新获取的数字比之前展示的数字多或少2时,显示“+2”或“-2”的动画效果
1. 创建独立的 AnimatedValue
组件
// components/AnimatedValue/index.jsx
import React, { useState, useEffect, useRef } from 'react';
import styles from './styles.module.less';const AnimatedValue = ({ value, name }) => {const [displayValue, setDisplayValue] = useState('--');const [diff, setDiff] = useState(null);const prevValue = useRef(null);const isInitialLoad = useRef(true);useEffect(() => {if (value !== undefined && value !== null) {const numValue = Number(value);// 只有在不是初始加载且前值存在时才计算差值if (!isInitialLoad.current && prevValue.current !== null) {const difference = numValue - prevValue.current;if (Math.abs(difference) >= 1) {setDiff(difference);// 3秒后清除差值显示const timer = setTimeout(() => setDiff(null), 3000);return () => clearTimeout(timer);}}prevValue.current = numValue;setDisplayValue(numValue);if (isInitialLoad.current) {isInitialLoad.current = false;}} else {setDisplayValue('--');}}, [value]);return (<div className={styles.value_container}><div className={styles.value}>{displayValue}</div>{diff !== null && (<div className={`${styles.diff_animation} ${diff > 0 ? styles.increase : styles.decrease}`}>{diff > 0 ? `+${diff}` : diff}</div>)}</div>);
};export default AnimatedValue;
2. 对应的样式文件
// components/AnimatedValue/styles.module.less
.value_container {position: relative;display: inline-block;min-width: 60px;height: 30px; // 固定高度防止布局抖动
}.value {display: inline-block;
}.diff_animation {position: absolute;right: -30px;top: 0;font-size: 14px;font-weight: bold;animation: fadeUp 1.5s ease-out forwards;will-change: transform, opacity;&.increase {color: #f5222d; // 红色表示增加}&.decrease {color: #52c41a; // 绿色表示减少}
}@keyframes fadeUp {0% {opacity: 1;transform: translateY(0);}70% {opacity: 1;}100% {opacity: 0;transform: translateY(-20px);}
}
3. 在父组件中使用
import React, { useState, useEffect } from 'react';
import { Row, Col } from 'antd';
import AnimatedValue from '@/components/AnimatedValue';
import styles from './yourStyles.module.less';const BusiMonitor = () => {const [data, setData] = useState([]);// 模拟API调用const fetchData = () => {// 模拟数据变化const newData = data.map(item => ({...item,value: Math.floor(Math.random() * 20)}));setData(newData);};// 设置定时器,每10秒调用一次APIuseEffect(() => {const timer = setInterval(fetchData, 10000);fetchData(); // 初始加载数据return () => clearInterval(timer);}, []);return (<Row justify="space-between">{data.map(({ name, value }, index) => (<Col ><div><div className={styles.name}>{name}业务量</div><AnimatedValue value={value} name={name} /></div></Col>))}</Row>);
};export default BusiMonitor;