vue中優(yōu)雅實現(xiàn)數(shù)字遞增特效的詳細過程
需求
前幾天項目開發(fā)中遇到一個需求,需要在數(shù)字更新時,實現(xiàn)其動態(tài)遞增的效果

并且,在數(shù)字大于10000時,將單位進行轉(zhuǎn)換,如數(shù)字大于10000時,單位從m²變?yōu)槿fm²

我們以vue中開發(fā)為例,一一實現(xiàn)下這兩個需求。
實現(xiàn)
基本開發(fā)思路
實現(xiàn)數(shù)字遞增,最容易的,我們應(yīng)該可以想到通過setinterval函數(shù)實現(xiàn)數(shù)字累加功能。比如,我們的最終值是finanllyNum, 我們可以很快想到這樣的函數(shù):
let finalNum = 1200
let count = 0
let timer = setInterval(() => {
count ++
if(count > finalNum){
// 避免count大于finalNum最終數(shù)字顯示不對
count = finalNum
// 清空定時器
clearInterval(timer)
timer = null
}
}, 10);這個代碼中,count是我們要實時在瀏覽器中顯示的數(shù)字。我們每10ms實現(xiàn)數(shù)字進行一次遞增,從而實現(xiàn)數(shù)字的動態(tài)遞增特效。
指令的開發(fā)
由于項目中涉及很多這樣的功能點,因此,這個功能應(yīng)該被統(tǒng)一進行封裝和復(fù)用。由于我們使用的是vue技術(shù)棧,顯然,通過vue中的指令來實現(xiàn)這個功能最合適。
以下實現(xiàn)方案基于vue指令實現(xiàn),因此,您需要參考官網(wǎng)了解學習vue中指令的基本用法。
vue2和vue3指令的用法大同小異,本示例以vue2進行演示
指令的基本結(jié)構(gòu)
首先,我們創(chuàng)建change.js文件,寫入指令的最基本結(jié)構(gòu)
// js實現(xiàn)動態(tài)變化的數(shù)字
const directive = {
inserted(el:any, binding:any) {
...
},
};
export default directivemain.js中引入該文件
import Vue from "vue";
import App from "./App.vue";
import directive from "./change";
Vue.config.productionTip = false;
// 注冊名為 change 的指令
Vue.directive("change", directive);
new Vue({
render: (h) => h(App),
}).$mount("#app");此時,我們創(chuàng)造了一個名為v-change的指令,我們直接使用
// App.vue
<template>
<div id="app">
<span> 240 </span>
</div>
</template>結(jié)合我們最開始的實現(xiàn)思路,可以完善指令
// js實現(xiàn)動態(tài)變化的數(shù)字
const directive = {
inserted(el, binding) {
// 獲取到需要動態(tài)變化的數(shù)值
let finalNum = el.innerText;
let count = 0;
let timer = setInterval(() => {
count++;
el.innerText = count;
if (count > finalNum) {
// 避免count大于finalNum最終數(shù)字顯示不對
count = finalNum;
el.innerText = count;
// 清空定時器
clearInterval(timer);
timer = null;
}
}, 10);
},
};
export default directive;打開瀏覽器,可以看到我們的指令基本完成了。

但目前這個指令有個非常大的問題。我們設(shè)置的是每10ms增加一下數(shù)字(數(shù)字加1),如果數(shù)字非常大比如為12000,那么這個數(shù)字的動態(tài)變化過程豈不是非常長?
我們應(yīng)該讓數(shù)字無論多大,都在指定時間完成才行。
指令的優(yōu)化
要想數(shù)字在指定時間完成變化,我們需要找到這個變化過程中的一些數(shù)學關(guān)系。目前,我們已經(jīng)知道的有變化初始值0,變化最終值12000,動畫總時長(假設(shè)為2S)。其次,每幀動畫的間隔時長也是我們應(yīng)該考慮的一個數(shù)值。
一開始的示例中,每10ms就是每幀動畫的間隔時長。
簡單理解,動畫的間隔時長就是每秒動畫變化的頻率
我們通過兩個圖來理解一下:
如圖,時間間隔為 166.7ms時,數(shù)字1s變化6次,分別為 100,200,300,400,500,600

當時間間隔為 100ms時,數(shù)字1s變化10次,以此為60,120,180,.......,600

可見,時間間隔越小,數(shù)字變化的也就越快。
現(xiàn)在我們可以得到這樣一個數(shù)學關(guān)系:
動畫總時長 / 時間間隔 * 數(shù)字的步長(每 1時間間隔增加的值) = 1200
現(xiàn)在,我們可以優(yōu)化一下指令了
// js實現(xiàn)動態(tài)變化的數(shù)字
const directive = {
inserted(el, binding) {
// 最終要顯示的數(shù)字
let finalNum = el.innerText;
// 動畫間隔
let rate = 30;
// 總時長
let time = 2000;
// 步長,數(shù)據(jù)增加間隔
let step = finalNum / (time / rate);
// 初始值
let count = 0;
// 要保留的小數(shù)
let timer = setInterval(() => {
count = count + step;
el.innerText = count.toFixed(0);
if (count > finalNum) {
// 避免count大于finalNum最終數(shù)字顯示不對
count = finalNum;
el.innerText = count;
// 清空定時器
clearInterval(timer);
timer = null;
}
}, rate);
},
};
export default directive;效果非常不錯!

實現(xiàn)單位變化
如何數(shù)字后面有單位,我們要怎么實現(xiàn)單位的變化呢?
第一種方法:
通過js動態(tài)為數(shù)字后賦值,這種方法很好理解
let timer = setInterval(() => {
count = count + step;
// 根據(jù)不同數(shù)值顯示不同單位
if( count < 1000 ){
el.innerText = count.toFixed(0) + "個"
}else{
el.innerText = (count / 1000 ).toFixed(0) + "千個"
}
if (count > finalNum) {
count = finalNum;
// 避免count大于finalNum最終數(shù)字顯示不對
if( count < 1000 ){
el.innerText = count.toFixed(0) + "個"
}else{
el.innerText = (count / 1000 ).toFixed(0) + "千個"
}
// 清空定時器
clearInterval(timer);
timer = null;
}
}, rate);
這個方法有一個很大的缺陷,就是單位必須寫死在指令里,如下圖,如果我們要實現(xiàn)很多動態(tài)數(shù)字而且需要不同單位該怎么辦呢?

第二種方法:
指令是可以傳遞參數(shù)的
<template>
<div id="app">
<div >
<span v-change="{eUnit:'個',eUnit:'萬個'}"> 1200 </span>
</div>
</div>
</template>通過binding.value可以接受參數(shù)。我們可以通過獲取的參數(shù),來處理邏輯,如下:
// js實現(xiàn)動態(tài)變化的數(shù)字
const directive = {
inserted(el, binding) {
// .....
let timer = setInterval(() => {
count = count + step;
if( count < 1000 ){
// binding.value.bUnit是我們通過指令傳遞進來的參數(shù)
el.innerText = count.toFixed(0) + binding.value.bUnit
}else{
el.innerText = (count / 1000 ).toFixed(0) + binding.value.eUnit
}
if (count > finalNum) {
// 避免count大于finalNum最終數(shù)字顯示不對
count = finalNum;
if( count < 1000 ){
el.innerText = count.toFixed(0) + binding.value.bUnit
}else{
el.innerText = (count / 1000 ).toFixed(0) + binding.value.eUnit
}
// 清空定時器
clearInterval(timer);
timer = null;
}
}, rate);
},
};
export default directive;當然,還有其他實現(xiàn)邏輯,也歡迎大家發(fā)揮自己的所長!
總結(jié)
到此這篇關(guān)于vue中優(yōu)雅實現(xiàn)數(shù)字遞增特效的文章就介紹到這了,更多相關(guān)vue數(shù)字遞增特效內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3和Electron實現(xiàn)桌面端應(yīng)用詳解
本文主要介紹了Vue3和Electron實現(xiàn)桌面端應(yīng)用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-07-07
詳解使用Vue Router導(dǎo)航鉤子與Vuex來實現(xiàn)后退狀態(tài)保存
本篇文章主要介紹了詳解使用Vue Router導(dǎo)航鉤子與Vuex來實現(xiàn)后退狀態(tài)保存,具有一定的參考價值,有興趣的可以了解一下2017-09-09

