在可視化展示界面時有一種場景,就是頁面在初始化的時候,有些數(shù)字展示想要從某個值開始動態(tài)遞增到實際值,形成一種動畫效果。例如:

數(shù)字動態(tài)遞增.gif
第一種情況:固定最大遞增過程時間
import { useEffect, useState } from 'react';
import { timer } from 'rxjs';
import { takeWhile } from 'rxjs/operators';
export const Counter = ({
counts,
time = 1000, // 默認1秒之內(nèi)整個動畫完成
}: {
counts: number;
time?: number;
}) => {
const [count, setCount] = useState(0);
useEffect(() => {
const step = counts <= time ? 1 : Math.ceil(counts / time); // 兩種情況:1.總數(shù)小于time時,就以每毫秒遞增1的形式增加;2.總數(shù)達于1000,計算出每毫秒至少要遞增多少。
const sub = timer(0, 1) // 設(shè)置一個定時器,每一毫秒執(zhí)行一次
.pipe(
takeWhile((val) => {
setCount((pre) => (pre + step > counts ? counts : pre + step));
return val < Math.min(counts, time); // 當(dāng)counts值小于time時,就只執(zhí)行行counts毫秒,達到counts就停止;如果counts值大于time,那就執(zhí)行time毫秒
})
)
.subscribe();
return () => sub.unsubscribe(); // 組件關(guān)閉時刪除掉timer
}, [counts]);
return <div>{count}</div>;
};
<Counter counts={452} />
這種處理方法的好處是,整個遞增動畫的時間可控,并且人性化的處理了有一些比較小的數(shù)字,沒必要通過變緩整個動畫效果來達到固定的動畫時間,如果頁面需要這個動畫效果的地方較多的時候,整個遞增的頻率是一致的,界面看起來也不會混亂。這種方法比較適合單純只是給頁面做一種動態(tài)特效,增加頁面豐富性。
第二種情況:固定步進
import { useEffect, useState } from 'react';
import { timer } from 'rxjs';
import { takeWhile } from 'rxjs/operators';
export const Counter = ({
counts,
step = 1,
}: {
counts: number;
step?: number;
}) => {
const [count, setCount] = useState(0);
useEffect(() => {
const t =
counts % step
? (counts + (step - (counts % step))) / step
: counts / step; // 求出具體需要遞增多少次
const sub = timer(0, 1)
.pipe(
takeWhile((val) => {
setCount((pre) => (pre + step > counts ? counts : pre + step)); // 遞增值大于counts時,設(shè)為counts
return val < t // 只執(zhí)行t毫秒
})
)
.subscribe();
return () => sub.unsubscribe();
}, []);
return <div>{count}</div>;
};
<Counter counts={4555} step={2} />
這種做法是把每次遞增的步進給固定了,每次必須增加這么多,在這種情況下,像我們上面的這種處理方式就是不固定具體整個動畫要進行多長時間,只需要看我們計算出來的遞增次數(shù)有多少次,那么就按照每一毫秒遞增的頻率遞增多少毫秒。
當(dāng)然,你還可以在這個基礎(chǔ)上繼續(xù)延伸,比如遞增步進固定的同時,把遞增最大時間也給固定了。。