vue实现数字翻牌器,数字滚动显示,数字动画显示 电脑版发表于:2023/3/11 13:01 效果如下: <img src="https://img.tnblog.net/arcimg/aojiancc2/0e36868f47a4402a9cbebc2a74e691ae.gif" width="260px"> ## 封装组件 ``` <template> <div class="number-grow-warp"> <span ref="numberGrow" :data-time="time" class="number-grow" :data-value="valnumber"></span> </div> </template> <script> export default { // 组件名字 name: 'NumberGrow', props: { time: { type: Number, default: 50 }, valnumber: { type: Number, default: 520 }, }, watch: { // watch第一次绑定值的时候不会执行监听,修改数据才会触发函数。数字变化的时候就出现翻牌动画 valnumber(newVal, oldVal) { // console.log(newVal) // console.log(oldVal) // 计算差值。不同的差值可以让间隔时间不一致 let shortValue = (newVal-oldVal) let jumpTime = 145 // 如果改变的数字大于30了,我们就把总时间控制到750毫秒。那么每步走的时间就是720/步数 if(shortValue>30) { jumpTime = 750/shortValue } // 如果改变的数字在20到30范围内,我们就把总时间控制到750毫秒 else if(shortValue>=20&&shortValue<=30) { jumpTime = 700/shortValue } // 如果改变的数字在10到20范围内,我们就把总时间控制到600毫秒 else if(shortValue>=10&&shortValue<20) { jumpTime = 600/shortValue } else if(shortValue>=5&&shortValue<10) { jumpTime = 500/shortValue } else { jumpTime=145 } this.numberGrow(this.$refs.numberGrow,oldVal,jumpTime) } }, methods: { numberGrow(ele,oldVal,jumpTime) { let _this = this // let step = (_this.valnumber * 10) / (_this.time * 1000) // // 步长可能是小数,需要处理一下,至少不能是小数,不然效果比较差 // if (step < 1) { // alert("步长小于1了") // step = 1 // } //步长就设置成1吧 let step= 1 // let current = 0 // let start = 0 // 不应该从0开始应该从上一次的值开始 let current = oldVal let start = oldVal let t = setInterval(function () { start += step if (start > _this.valnumber) { clearInterval(t) start = _this.valnumber t = null } if (current === start) { return } //console.log(start) current = start ele.innerHTML = current // 格式化一下计数法,三位加一个逗号分隔 // ele.innerHTML = current.toString().replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, '$1,') }, jumpTime) } }, mounted() { // this.numberGrow(this.$refs.numberGrow) this.$refs.numberGrow.innerHTML = this.valnumber } } </script> <style> .number-grow-warp { transform: translateZ(0); } .number-grow { font-family: Arial-BoldMT; font-size: 30px; color: #ffaf00; letter-spacing: 2.67px; margin: 110px 0 20px; display: block; line-height: 64px; } </style> ``` **上面那个没有实现数字变小的动画,需要写一下判断,每次递减就行了** ``` <template> <div class="number-grow-warp"> <span ref="numberGrow" :data-time="time" class="number-grow" :data-value="valnumber"></span> </div> </template> <script> export default { // 组件名字 name: 'NumberGrow', props: { time: { type: Number, default: 50 }, valnumber: { type: Number, default: 720000 }, }, watch: { // watch第一次绑定值的时候不会执行监听,修改数据才会触发函数。数字变化的时候就出现翻盘动画 valnumber(newVal, oldVal) { // console.log(newVal) // console.log(oldVal) // 计算差值。不同的差值可以让间隔时间不一致 let shortValue = (newVal - oldVal) // 默认是加法 let changeType = "add" if (shortValue < 0) { shortValue = -(shortValue) // 如果变化是负数就变成减法 changeType = "subtraction" } let jumpTime = 145 // 如果改变的数字大于30了,我们就把总时间控制到750毫秒。那么每步走的时间就是720/步数 if (shortValue > 30) { jumpTime = 750 / shortValue } // 如果改变的数字在20到30范围内,我们就把总时间控制到750毫秒 else if (shortValue >= 20 && shortValue <= 30) { jumpTime = 700 / shortValue } // 如果改变的数字在10到20范围内,我们就把总时间控制到600毫秒 else if (shortValue >= 10 && shortValue < 20) { jumpTime = 600 / shortValue } else if (shortValue >= 5 && shortValue < 10) { jumpTime = 500 / shortValue } else { jumpTime = 145 } if (changeType === "add") { this.numberGrow(this.$refs.numberGrow, oldVal, jumpTime) } else { this.numberReduce(this.$refs.numberGrow, oldVal, jumpTime) } } }, methods: { //数字变大 numberGrow(ele, oldVal, jumpTime, changeType) { let _this = this // let step = (_this.valnumber * 10) / (_this.time * 1000) // // 步长可能是小数,需要处理一下,至少不能是小数,不然效果比较差 // if (step < 1) { // alert("步长小于1了") // step = 1 // } //步长就设置成1吧 let step = 1 if (changeType === "subtraction") { step = -1 } // let current = 0 // let start = 0 // 不应该从0开始应该从上一次的值开始 let current = oldVal let start = oldVal let t = setInterval(function () { start += step if (start > _this.valnumber) { clearInterval(t) start = _this.valnumber t = null } if (current === start) { return } //console.log(start) current = start ele.innerHTML = current // 格式化一下计数法,三位加一个逗号分隔 // ele.innerHTML = current.toString().replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, '$1,') }, jumpTime) }, //数字变小 numberReduce(ele, oldVal, jumpTime) { let _this = this let step = -1 let current = oldVal let start = oldVal let t = setInterval(function () { start += step if (start <= _this.valnumber) { clearInterval(t) start = _this.valnumber t = null } if (current === start) { return } current = start ele.innerHTML = current }, jumpTime) }, }, mounted() { // this.numberGrow(this.$refs.numberGrow) this.$refs.numberGrow.innerHTML = this.valnumber } } </script> <style> .number-grow-warp { transform: translateZ(0); } .number-grow { font-family: Arial-BoldMT; font-size: 30px; color: #23FFFC; /* letter-spacing: 2.67px; */ /* margin: 110px 0 20px; */ display: block; height: 60px; line-height: 60px; } </style> ``` #### 优化数字变化大导致比较久才能显示完的问题 如果数字变化大,时间间隔太短了,在那个间隔时间不一定走得完,所以时间间隔太小了,每次得步长就不能是1了,要加大一点,比如数字从0变化到37362,每次+1的时间要0.02毫秒才能到750毫秒之内走完,但是0.02毫秒是无法进行一次+1显示的,普通计算机显示器在进行一次切换显示的时间是远大于0.02毫秒的。 所以我们可以把时间和每次变化的数字同步扩大就行。比如0.02毫秒每次+1,同步扩大50倍,就变成了,1毫秒每次+50,这样还是可以保存在总时间不变的情况下,数字增加完成,只是每步数字变化变大了些,当然对应的时间间隔变大了。 ``` <template> <div class="number-grow-warp"> <span ref="numberGrow" :data-time="time" class="number-grow" :data-value="valnumber"></span> </div> </template> <script> export default { // 组件名字 name: 'NumberGrow', props: { time: { type: Number, default: 50 }, valnumber: { type: Number, default: 0 }, }, watch: { // watch第一次绑定值的时候不会执行监听,修改数据才会触发函数。数字变化的时候就出现翻牌动画 valnumber(newVal, oldVal) { // console.log(newVal) // console.log(oldVal) // 计算差值。不同的差值可以让间隔时间不一致 let shortValue = (newVal - oldVal) // console.log("...............数字差值.................") // console.log(shortValue) // 默认是加法 let changeType = "add" if (shortValue < 0) { shortValue = -(shortValue) // 如果变化是负数就变成减法 changeType = "subtraction" } let jumpTime = 145 let jumpNumber =1 if (shortValue > 750) { /* 时间间隔太短了,在那个间隔时间不一定走得完,所以时间间隔太小了,每次得步长就不能是1了,要加大一点, 比如数字从0变化到37362,每次+1的时间要0.02毫秒才能到720毫秒之内走完,但是0.02毫秒是无法进行一次+1显示的,普通计算机显示器在进行一次切换显示的时间是大于0.02毫秒的 所以我们可以把时间和每次变化的数字同步扩大就行。比如0.02毫秒每次+1,同步扩大50倍,就变成了,1毫秒每次+50, 这样还是可以保存在总时间不变的情况下,数字增加完成,只是每步数字变化变大了些,当然对应的时间间隔变大了。 */ jumpTime = 750 / shortValue // 扩大的倍数就安装750的倍数来吧,我们差不多控制到1毫秒进行一次数字改变 let n = Math.round(shortValue/750) console.log("每次间隔应该扩大:"+n+"倍") // 进行一次数字改变的数值扩大n倍 jumpNumber = jumpNumber*n // 时间间隔也同步扩大n倍 jumpTime = jumpTime*n } // 如果改变的数字大于30了,我们就把总时间控制到750毫秒。那么每步走的时间就是720/步数 else if (shortValue > 30) { jumpTime = 750 / shortValue // console.log(".....每步的时间....") // console.log(jumpTime) } // 如果改变的数字在20到30范围内,我们就把总时间控制到750毫秒 else if (shortValue >= 20 && shortValue <= 30) { jumpTime = 700 / shortValue } // 如果改变的数字在10到20范围内,我们就把总时间控制到600毫秒 else if (shortValue >= 10 && shortValue < 20) { jumpTime = 600 / shortValue } else if (shortValue >= 5 && shortValue < 10) { jumpTime = 500 / shortValue } else { jumpTime = 145 } if (changeType === "add") { this.numberGrow(this.$refs.numberGrow, oldVal, jumpTime,jumpNumber) } else { this.numberReduce(this.$refs.numberGrow, oldVal, jumpTime,jumpNumber) } } }, methods: { //数字变大 numberGrow(ele, oldVal, jumpTime, jumpNumber) { let _this = this // let step = (_this.valnumber * 10) / (_this.time * 1000) // // 步长可能是小数,需要处理一下,至少不能是小数,不然效果比较差 // if (step < 1) { // alert("步长小于1了") // step = 1 // } //步长就设置成1吧 // let step = 1 let step = jumpNumber // if (changeType === "subtraction") { // step = -1 // } // let current = 0 // let start = 0 // 不应该从0开始应该从上一次的值开始 let current = oldVal let start = oldVal let t = setInterval(function () { start += step if (start > _this.valnumber) { clearInterval(t) start = _this.valnumber t = null } if (current === start) { return } //console.log(start) current = start ele.innerHTML = current // 格式化一下计数法,三位加一个逗号分隔。千分号 //ele.innerHTML = current.toString().replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, '$1,') }, jumpTime) }, //数字变小 numberReduce(ele, oldVal, jumpTime,jumpNumber) { let _this = this // let step = -1 // 取负数 let step = 0-jumpNumber let current = oldVal let start = oldVal let t = setInterval(function () { start += step if (start <= _this.valnumber) { clearInterval(t) start = _this.valnumber t = null } if (current === start) { return } current = start ele.innerHTML = current }, jumpTime) }, }, mounted() { // this.numberGrow(this.$refs.numberGrow) this.$refs.numberGrow.innerHTML = this.valnumber } } </script> <style> .number-grow-warp { transform: translateZ(0); } .number-grow { font-family: Arial-BoldMT; font-size: 29px; color: #23FFFC; /* letter-spacing: 2.67px; */ /* margin: 110px 0 20px; */ display: block; height: 60px; line-height: 60px; } </style> ``` 还需要继续完善,比如字体,字号,风格等这些作为参数会更通用,还有逻辑也是现在还是写得很粗糙 #### 优化在短时间内多次改变造成的显示问题 比如前面变化还没有完成,数字马上又变成了就会有问题,比如先从0到5,然后0到5还没有改变完成在变化到500,然后马上又变化到1000。这样的话其实有三个定时器在改变数字,第一次是从0?5,然后就是从5?500,在就是从500?1000。我们看数字变化的效果是这样的,先慢慢一个数字一个数字的再走,然后很快的加速到500,然后又数字减少到几十然后加速到1000然后又减少到几十多一点,又开始慢慢走。感觉每次变化的新的数字都不是前面赋值的而是最新赋值的一次,果然是我封装的时候只传递了旧值,根本没有传递新的值 ![](https://img.tnblog.net/arcimg/aojiancc2/60640558215345028ec6bf8e209cecf1.png) 看一下新的值是直接取的绑定的那个值,这肯定不行撒,如果多次都在运行中,就会出现刚刚运行的情况,每次都要变化的最新的值去 ![](https://img.tnblog.net/arcimg/aojiancc2/5dd9e9f4a5c64c0fb92a0bf92880fa99.png) 如果以很慢的速度变化到很大的值去就会很有问题了,数字大了走几个小时都有可能,所以每次改变的数字应该只影响本次的,新值也需要改成进行传递的方式 ![](https://img.tnblog.net/arcimg/aojiancc2/c323c99463884ebcb68de21f57ba485f.png) **贴一下代码** 这里还实现了一下是否使用默认样式的配置 ``` <template> <div class="number-grow-warp"> <!-- <span ref="numberGrow" :data-time="time" class="number-grow" :data-value="valnumber"></span> --> <!-- 样式变成可以绑定的,引用组件的时候可以不要这个样式 --> <span ref="numberGrow" :data-time="time" :class="defaultClass" :data-value="valnumber"></span> </div> </template> <script> export default { // 组件名字 name: 'NumberGrow', props: { time: { type: Number, default: 50 }, valnumber: { type: Number, default: 0 }, // 默认样式。组件内容提供了一套默认样式,如果引用组件的时候不想使用这个样式就可以修改这个参数 defaultClass: { type: String, default: 'number-grow' } }, data() { return { // 上次的数字变化是否已经完成,比如第一次从0到500都还没有变化完成,又要变成1000,这种就应该等待第一次运行完成后才去执行第二次的变成 isLastStop: true, } }, watch: { // watch第一次绑定值的时候不会执行监听,修改数据才会触发函数。数字变化的时候就出现翻牌动画 valnumber(newVal, oldVal) { // console.log(newVal) // console.log(oldVal) // 判断是否上次已经改变完成了 // if (this.isLastStop === true) { //console.log("上一次运行完成了"+newVal+","+oldVal) this.isLastStop = false // 计算差值。不同的差值可以让间隔时间不一致 let shortValue = (newVal - oldVal) // console.log("...............数字差值.................") // console.log(shortValue) // 默认是加法 let changeType = "add" if (shortValue < 0) { shortValue = -(shortValue) // 如果变化是负数就变成减法 changeType = "subtraction" } let jumpTime = 145 let jumpNumber = 1 if (shortValue > 750) { /* 时间间隔太短了,在那个间隔时间不一定走得完,所以时间间隔太小了,每次得步长就不能是1了,要加大一点, 比如数字从0变化到37362,每次+1的时间要0.02毫秒才能到720毫秒之内走完,但是0.02毫秒是无法进行一次+1显示的,普通计算机显示器在进行一次切换显示的时间是大于0.02毫秒的 所以我们可以把时间和每次变化的数字同步扩大就行。比如0.02毫秒每次+1,同步扩大50倍,就变成了,1毫秒每次+50, 这样还是可以保存在总时间不变的情况下,数字增加完成,只是每步数字变化变大了些,当然对应的时间间隔变大了。 */ jumpTime = 750 / shortValue // 扩大的倍数就安装750的倍数来吧,我们差不多控制到1毫秒进行一次数字改变 let n = Math.round(shortValue / 750) //console.log("每次间隔应该扩大:"+n+"倍") // 进行一次数字改变的数值扩大n倍 jumpNumber = jumpNumber * n // 时间间隔也同步扩大n倍 jumpTime = jumpTime * n } // 如果改变的数字大于30了,我们就把总时间控制到750毫秒。那么每步走的时间就是750/步数 else if (shortValue > 30) { jumpTime = 750 / shortValue } // 如果改变的数字在20到30范围内,我们就把总时间控制到750毫秒 else if (shortValue >= 20 && shortValue <= 30) { jumpTime = 700 / shortValue } // 如果改变的数字在10到20范围内,我们就把总时间控制到600毫秒 else if (shortValue >= 10 && shortValue < 20) { jumpTime = 600 / shortValue } // 如果改变的数字在3到10范围内,我们就把总时间控制到530毫秒 else if (shortValue >= 2 && shortValue < 10) { jumpTime = 530 / shortValue } else { //jumpTime = 145 // 修改大一点吧,变化效果明显点,不然变化少了,看着一点都不明显 jumpTime = 266 } if (changeType === "add") { this.numberGrow(this.$refs.numberGrow, oldVal, jumpTime, jumpNumber, newVal) } else { this.numberReduce(this.$refs.numberGrow, oldVal, jumpTime, jumpNumber, newVal) } // } // else // { // console.log("上一次还没有运行完成"+newVal+","+oldVal) // } } }, methods: { //数字变大 numberGrow(ele, oldVal, jumpTime, jumpNumber, newVal) { let _this = this //步长就设置成1吧 // let step = 1 let step = jumpNumber // 不应该从0开始应该从上一次的值开始 let current = oldVal let start = oldVal // 试试先清除一下上次还没有执行完的定时器了 // clearInterval(t) let t = setInterval(function () { start += step if (start > newVal) { clearInterval(t) start = newVal t = null _this.isLastStop = true } if (current === start) { return } //console.log(start) current = start ele.innerHTML = current // 格式化一下计数法,三位加一个逗号分隔。千分号 //ele.innerHTML = current.toString().replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, '$1,') }, jumpTime) }, //数字变小 numberReduce(ele, oldVal, jumpTime, jumpNumber, newVal) { let _this = this // let step = -1 // 取负数 let step = 0 - jumpNumber let current = oldVal let start = oldVal // 试试先清除一下上次还没有执行完的定时器了 // clearInterval(t) let t = setInterval(function () { start += step if (start <= newVal) { clearInterval(t) start = newVal t = null _this.isLastStop = true } if (current === start) { return } current = start ele.innerHTML = current }, jumpTime) }, }, mounted() { // this.numberGrow(this.$refs.numberGrow) this.$refs.numberGrow.innerHTML = this.valnumber } } </script> <style scoped> .number-grow-warp { transform: translateZ(0); } .number-grow { font-family: Arial-BoldMT; font-size: 29px; color: #23FFFC; display: block; height: 60px; line-height: 60px; } </style> ``` 但是要注意一下会不会出现这种情况就是三次改变,照理说应该是最后一次最后完成,数字也是最后的值,但是前面的由于执行慢,反而变成了最后执行完成了,那么最后剩下的值就会有问题了,其实只要保证数字变化小的执行时机小于数字变化大的就行了,而且两次改变数字之间也是存在时间差的,所以保证这两点就不会出现上面说的情况。 #### 继续优化可以在多个改变同时进行的时候,变成只有一个定时器在运行,停掉上一次的 比如第二个在进行改变的时候发现上一次的定时器还没有执行完成就直接停掉上一次的,马上开始这一次的改变,保证每次只有一个定时任务在执行,就不会出现那种几个定时器同时在执行,数字一会变大又变小然后在变大的情况了,这样情况的显示看起来就不是太舒服了,虽然不影响最后数字的正确性。 **先定义一个变量记录一下定时器:** ![](https://img.tnblog.net/arcimg/aojiancc2/7f5aac8f6e3c407992831dadcb86b8c8.png) **然后涉及到定时器的地方都换成这个变量:** ![](https://img.tnblog.net/arcimg/aojiancc2/ea6e4341ad544837b79c573245b3ce7f.png) **然后在数字改变的时候判断一下,上一次是否执行完成,如果这一次要开始执行了,上一次的还没有执行完成的话,直接把上一次执行中的定时器干掉就行了,直接开始这一次的变化就行了** ![](https://img.tnblog.net/arcimg/aojiancc2/b71e0c2f74f6488495ef42872113a69c.png) 因为其实每次都是从一个数字变成需要的新数字,那么肯定是以最新的为准就行了,那么既然新的一次都开始了前面的在继续去执行就没有意义了,还会很影响美观,所以如果上一次还没有执行完毕直接干掉即可 **贴一下代码:** ``` <template> <div class="number-grow-warp"> <!-- <span ref="numberGrow" :data-time="time" class="number-grow" :data-value="valnumber"></span> --> <!-- 样式变成可以绑定的,引用组件的时候可以不要这个样式 --> <span ref="numberGrow" :data-time="time" :class="defaultClass" :data-value="valnumber"></span> </div> </template> <script> export default { // 组件名字 name: 'NumberGrow', props: { time: { type: Number, default: 50 }, valnumber: { type: Number, default: 0 }, // 默认样式。组件内容提供了一套默认样式,如果引用组件的时候不想使用这个样式就可以修改这个参数 defaultClass: { type: String, default: 'number-grow' } }, data() { return { // 上次的数字变化是否已经完成,比如第一次从0到500都还没有变化完成,又要变成1000,这种就应该等待第一次运行完成后才去执行第二次的变成() //isLastStop: true, // 定时器记录一下,方便判断上一次还没有运行完成的情况 myInterval:null } }, watch: { // watch第一次绑定值的时候不会执行监听,修改数据才会触发函数。数字变化的时候就出现翻牌动画 valnumber(newVal, oldVal) { // console.log(newVal) // console.log(oldVal) // 说明上次的运行还没有执行完毕 if(this.myInterval!=null) { //直接清楚掉上一次的运行 clearInterval(this.myInterval) // 设置成执行完毕的效果 //this.valnumber = oldVal //this.$refs.numberGrow.innerHTML = this.valnumber } // 判断是否上次已经改变完成了 // if (this.isLastStop === true) { //console.log("上一次运行完成了"+newVal+","+oldVal) // this.isLastStop = false // 计算差值。不同的差值可以让间隔时间不一致 let shortValue = (newVal - oldVal) // console.log("...............数字差值.................") // console.log(shortValue) // 默认是加法 let changeType = "add" if (shortValue < 0) { shortValue = -(shortValue) // 如果变化是负数就变成减法 changeType = "subtraction" } let jumpTime = 145 let jumpNumber = 1 if (shortValue > 750) { /* 时间间隔太短了,在那个间隔时间不一定走得完,所以时间间隔太小了,每次得步长就不能是1了,要加大一点, 比如数字从0变化到37362,每次+1的时间要0.02毫秒才能到720毫秒之内走完,但是0.02毫秒是无法进行一次+1显示的,普通计算机显示器在进行一次切换显示的时间是大于0.02毫秒的 所以我们可以把时间和每次变化的数字同步扩大就行。比如0.02毫秒每次+1,同步扩大50倍,就变成了,1毫秒每次+50, 这样还是可以保存在总时间不变的情况下,数字增加完成,只是每步数字变化变大了些,当然对应的时间间隔变大了。 */ jumpTime = 750 / shortValue // 扩大的倍数就安装750的倍数来吧,我们差不多控制到1毫秒进行一次数字改变 let n = Math.round(shortValue / 750) //console.log("每次间隔应该扩大:"+n+"倍") // 进行一次数字改变的数值扩大n倍 jumpNumber = jumpNumber * n // 时间间隔也同步扩大n倍 jumpTime = jumpTime * n } // 如果改变的数字大于30了,我们就把总时间控制到750毫秒。那么每步走的时间就是750/步数 else if (shortValue > 30) { jumpTime = 750 / shortValue } // 如果改变的数字在20到30范围内,我们就把总时间控制到750毫秒 else if (shortValue >= 20 && shortValue <= 30) { jumpTime = 700 / shortValue } // 如果改变的数字在10到20范围内,我们就把总时间控制到600毫秒 else if (shortValue >= 10 && shortValue < 20) { jumpTime = 600 / shortValue } // 如果改变的数字在3到10范围内,我们就把总时间控制到530毫秒 else if (shortValue >= 2 && shortValue < 10) { jumpTime = 530 / shortValue } else { //jumpTime = 145 // 修改大一点吧,变化效果明显点,不然变化少了,看着一点都不明显 jumpTime = 266 } if (changeType === "add") { this.numberGrow(this.$refs.numberGrow, oldVal, jumpTime, jumpNumber, newVal) } else { this.numberReduce(this.$refs.numberGrow, oldVal, jumpTime, jumpNumber, newVal) } // } // else // { // console.log("上一次还没有运行完成"+newVal+","+oldVal) // } } }, methods: { //数字变大 numberGrow(ele, oldVal, jumpTime, jumpNumber, newVal) { let _this = this // let step = (_this.valnumber * 10) / (_this.time * 1000) // // 步长可能是小数,需要处理一下,至少不能是小数,不然效果比较差 // if (step < 1) { // alert("步长小于1了") // step = 1 // } //步长就设置成1吧 // let step = 1 let step = jumpNumber // 不应该从0开始应该从上一次的值开始 let current = oldVal let start = oldVal // 试试先清除一下上次还没有执行完的定时器了 // clearInterval(t) _this.myInterval = setInterval(function () { start += step if (start > newVal) { clearInterval(_this.myInterval) start = newVal // t = null _this.myInterval = null // _this.isLastStop = true } if (current === start) { return } //console.log(start) current = start ele.innerHTML = current // 格式化一下计数法,三位加一个逗号分隔。千分号 //ele.innerHTML = current.toString().replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, '$1,') }, jumpTime) }, //数字变小 numberReduce(ele, oldVal, jumpTime, jumpNumber, newVal) { let _this = this // let step = -1 // 取负数 let step = 0 - jumpNumber let current = oldVal let start = oldVal // 试试先清除一下上次还没有执行完的定时器了 // clearInterval(t) _this.myInterval = setInterval(function () { start += step if (start <= newVal) { clearInterval(_this.myInterval) start = newVal // t = null _this.myInterval = null //_this.isLastStop = true } if (current === start) { return } current = start ele.innerHTML = current }, jumpTime) }, }, mounted() { // this.numberGrow(this.$refs.numberGrow) this.$refs.numberGrow.innerHTML = this.valnumber } } </script> <style scoped> .number-grow-warp { transform: translateZ(0); } .number-grow { font-family: Arial-BoldMT; font-size: 29px; color: #23FFFC; /* letter-spacing: 2.67px; */ /* margin: 110px 0 20px; */ display: block; height: 60px; line-height: 60px; } </style> ``` ## 使用组件 ``` <!-- 分析趋势 --> <template> <div> <div class="analyseTrend"> <div class="analyseTrend_warp"> <div class="analyseTrend_content_left"> <div class="analyseTrend_content_tag">知识点数</div> <div style="display: flex;"> <NumberGrow :valnumber="evalData.evalCount"></NumberGrow> <div class="analyseTrend_conten_unit">个</div> </div> </div> <div class="analyseTrend_content_right"> <div class="analyseTrend_content_tag">评估累计</div> <div style="display: flex;"> <NumberGrow :valnumber="evalData.evalDoCount"></NumberGrow> <div class="analyseTrend_conten_unit">人次</div> </div> </div> </div> <div class="splitline"></div> <div class="analyseTrend_warp"> <div class="analyseTrend_content_left"> <div class="analyseTrend_content_tag">实验数</div> <div style="display: flex;"> <NumberGrow :valnumber="labroomData.labroomCount"></NumberGrow> <div class="analyseTrend_conten_unit">个</div> </div> </div> <div class="analyseTrend_content_right"> <div class="analyseTrend_content_tag">实验累计人次</div> <div style="display: flex;"> <NumberGrow :valnumber="labroomData.labroomStuCount"></NumberGrow> <div class="analyseTrend_conten_unit">人次</div> </div> </div> </div> <div class="splitline"></div> <div class="analyseTrend_warp"> <div class="analyseTrend_content_left"> <div class="analyseTrend_content_tag">项目数</div> <div style="display: flex;"> <NumberGrow :valnumber="prodData.prodCount"></NumberGrow> <div class="analyseTrend_conten_unit">个</div> </div> </div> <div class="analyseTrend_content_right"> <div class="analyseTrend_content_tag">项目累计人次</div> <div style="display: flex;"> <NumberGrow :valnumber="prodData.prodStuCount"></NumberGrow> <div class="analyseTrend_conten_unit">人次</div> </div> </div> </div> </div> </div> </template> <script > import NumberGrow from '@/views/component/numberGrow.vue' export default { components: { NumberGrow }, // 组件名字 name: 'IntegratedData', // 组件参数 props: { }, data() { return { evalData:{ evalCount:3212, evalDoCount:1678467 }, labroomData: { labroomCount:5985, labroomStuCount:2897678 }, prodData:{ prodCount:3212, prodStuCount:1678467 } } }, mounted() { // 模拟数据变化 setInterval(() => { let becorevalprodStuCount = this.prodData.prodStuCount this.prodData.prodStuCount=becorevalprodStuCount+60 let becoreval = this.prodData.prodCount this.prodData.prodCount=becoreval+100 let beforeevalData = this.evalData.evalDoCount this.evalData.evalDoCount=beforeevalData+50 let beforeevalDatalabroomData = this.labroomData.labroomCount this.labroomData.labroomCount=beforeevalDatalabroomData+50 let labroomStuCount = this.labroomData.labroomStuCount this.labroomData.labroomStuCount=labroomStuCount+50 let beforeevalDataevalCount = this.evalData.evalCount this.evalData.evalCount=beforeevalDataevalCount+70 }, 2000); // setInterval(() => { // let val = this.numberData.labroom.number[0] // this.numberData.labroom.number[0] = val + 100 // //相当于复制了一份新的对象在给自己 // this.numberData.labroom = { ...this.numberData.labroom } // let prodval = this.numberData.prod.number[0] // this.numberData.prod.number[0] = prodval + 100 // this.numberData.prod = { ...this.numberData.prod } // // console.log(val) // // console.log("------------------") // }, 1800) }, beforeDestroy() { }, methods: { } } </script> <style lang="scss" scoped> // 分割线渐变 两边浅中间深 .splitline { height: 1px; // background: radial-gradient(#3FDDFA -54%, #fff 100%); // background:linear-gradient(to left,#fff,#3FDDFA,#fff); background: linear-gradient(to left, rgba(63, 221, 250, 0), #3FDDFA 50%, rgba(63, 221, 250, 0)); // background:linear-gradient(to left,rgba(63, 221, 250, 0) 0%,#3FDDFA 50%,rgba(63, 221, 250, 0) 100%); } .analyseTrend { margin-top: 26px; // margin-left: -10px; .analyseTrend_warp { height: 136px; display: flex; align-items: center; .analyseTrend_content_left { width: 150px; } .analyseTrend_content_right { width: 160px; } .analyseTrend_content_tag { font-size: 16px } // 单位 .analyseTrend_conten_unit { height: 60px; line-height: 60px; padding-top: 10px; color: #23FFFC; font-size: 15px; } } } </style> ```