vue中优雅实现数字递增特效的详细过程
目录
- 需求
- 实现
- 基本开发思路
- 指令的开发
- 指令的基本结构
- 指令的优化
- 实现单位变化
- 总结
需求
前几天项目开发中遇到一个需求,需要在数字更新时,实现其动态递增的效果
并且,在数字大于10000时,将单位进行转换,如数字大于10000时,单位从m²变为万m²
我们以vue中开发为例,一一实现下这两个需求。
实现
基本开发思路
实现数字递增,最容易的,我们应该可以想到通过setinterval函数实现数字累加功能。比如,我们的最终值是finanllyNum, 我们可以很快想到这样的函数:
let finalNum = 1200 let count = 0 let timer = setInterval(() => { count ++ if(count > finalNum){ // 避免count大于finalNum最终数字显示不对 count = finalNum // 清空定时器 clearInterval(timer) timer = null } }, 10);
这个代码中,count是我们要实时在浏览器中显示的数字。我们每10ms实现数字进行一次递增,从而实现数字的动态递增特效。
指令的开发
由于项目中涉及很多这样的功能点,因此,这个功能应该被统一进行封装和复用。由于我们使用的是vue技术栈,显然,通过vue中的指令来实现这个功能最合适。
以下实现方案基于vue指令实现,因此,您需要参考官网了解学习vue中指令的基本用法。
vue2和vue3指令的用法大同小异,本示例以vue2进行演示
指令的基本结构
首先,我们创建change.js文件,写入指令的最基本结构
// js实现动态变化的数字 const directive = { inserted(el:any, binding:any) { ... }, }; export default directive
main.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");
此时,我们创造了一个名为v-change的指令,我们直接使用
// App.vue <template> <div id="app"> <span> 240 </span> </div> </template>
结合我们最开始的实现思路,可以完善指令
// js实现动态变化的数字 const directive = { inserted(el, binding) { // 获取到需要动态变化的数值 let finalNum = el.innerText; let count = 0; let timer = setInterval(() => { count++; el.innerText = count; if (count > finalNum) { // 避免count大于finalNum最终数字显示不对 count = finalNum; el.innerText = count; // 清空定时器 clearInterval(timer); timer = null; } }, 10); }, }; export default directive;
打开浏览器,可以看到我们的指令基本完成了。
但目前这个指令有个非常大的问题。我们设置的是每10ms增加一下数字(数字加1),如果数字非常大比如为12000,那么这个数字的动态变化过程岂不是非常长?
我们应该让数字无论多大,都在指定时间完成才行。
指令的优化
要想数字在指定时间完成变化,我们需要找到这个变化过程中的一些数学关系。目前,我们已经知道的有变化初始值0,变化最终值12000,动画总时长(假设为2S)。其次,每帧动画的间隔时长也是我们应该考虑的一个数值。
一开始的示例中,每10ms就是每帧动画的间隔时长。
简单理解,动画的间隔时长就是每秒动画变化的频率
我们通过两个图来理解一下:
如图,时间间隔为 166.7ms时,数字1s变化6次,分别为 100,200,300,400,500,600
当时间间隔为 100ms时,数字1s变化10次,以此为60,120,180,.......,600
可见,时间间隔越小,数字变化的也就越快。
现在我们可以得到这样一个数学关系:
动画总时长 / 时间间隔 * 数字的步长(每 1时间间隔增加的值) = 1200
现在,我们可以优化一下指令了
// js实现动态变化的数字 const directive = { inserted(el, binding) { // 最终要显示的数字 let finalNum = el.innerText; // 动画间隔 let rate = 30; // 总时长 let time = 2000; // 步长,数据增加间隔 let step = finalNum / (time / rate); // 初始值 let count = 0; // 要保留的小数 let timer = setInterval(() => { count = count + step; el.innerText = count.toFixed(0); if (count > finalNum) { // 避免count大于finalNum最终数字显示不对 count = finalNum; el.innerText = count; // 清空定时器 clearInterval(timer); timer = null; } }, rate); }, }; export default directive;
效果非常不错!
实现单位变化
如何数字后面有单位,我们要怎么实现单位的变化呢?
第一种方法:
通过js动态为数字后赋值,这种方法很好理解
let timer = setInterval(() => { count = count + step; // 根据不同数值显示不同单位 if( count < 1000 ){ el.innerText = count.toFixed(0) + "个" }else{ el.innerText = (count / 1000 ).toFixed(0) + "千个" } if (count > finalNum) { count = finalNum; // 避免count大于finalNum最终数字显示不对 if( count < 1000 ){ el.innerText = count.toFixed(0) + "个" }else{ el.innerText = (count / 1000 ).toFixed(0) + "千个" } // 清空定时器 clearInterval(timer); timer = null; } }, rate);
这个方法有一个很大的缺陷,就是单位必须写死在指令里,如下图,如果我们要实现很多动态数字而且需要不同单位该怎么办呢?
第二种方法:
指令是可以传递参数的
<template> <div id="app"> <div > <span v-change="{eUnit:'个',eUnit:'万个'}"> 1200 </span> </div> </div> </template>
通过binding.value可以接受参数。我们可以通过获取的参数,来处理逻辑,如下:
// js实现动态变化的数字 const directive = { inserted(el, binding) { // ..... let timer = setInterval(() => { count = count + step; if( count < 1000 ){ // binding.value.bUnit是我们通过指令传递进来的参数 el.innerText = count.toFixed(0) + binding.value.bUnit }else{ el.innerText = (count / 1000 ).toFixed(0) + binding.value.eUnit } if (count > finalNum) { // 避免count大于finalNum最终数字显示不对 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;
当然,还有其他实现逻辑,也欢迎大家发挥自己的所长!
总结
到此这篇关于vue中优雅实现数字递增特效的文章就介绍到这了,更多相关vue数字递增特效内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!