分析拆解
数字变更的整个周期,主要分为三个状态。
- 数字的初始状态(即原始值
- 数字变化中的状态(原始值到新赋值之间的变动
- 数字的结束状态(即新赋值
状态的变化可能性
- 数字一次性由少变到多,或者由多变到少
- 数字变化状态中,多次改变结束状态的值
这里解释下两种变化可能性,第一种就是说,数字的变化从少到多或者从多到少,都是一次性变化,中间不会有任何干扰。而第二种,打个比方,初始值为1,新赋值为10,数字在从1到10的渐变中,还没有变化完全,仅仅变到了7的时候,就被用户再一次改变了新赋值为5或者20(即可能比第一个新赋值低,也可能高)。这个时候,应该顺应此时已经变化到的数值7,以7为起点,向着5或者20去渐增或者渐减。不然,重新以1为起点开始向5或者20进行变化,就会有违和感。而顺应已经变化到的值进行变化,即便中途进行了再多次数值变更,整体的变化仍是流畅自然的。
代码实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>数值变化测试demo</title> <style> html, body { margin: 0; padding: 0; height: 100%; width: 100%; background-color: cornflowerblue; } #app { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; flex-wrap: wrap; align-content: center; } .num { width: 100%; font-size: 100px; margin-bottom: 15px; text-align: center; } </style> </head> <body> <div id="app"> <div class="num">{{ num.a }}</div> <button class="btn" @click="change(1)">1</button> <button class="btn" @click="change(5)">5</button> <button class="btn" @click="change(10)">10</button> <button class="btn" @click="change(20)">20</button> <button class="btn" @click="change(50)">50</button> <button class="btn" @click="change(75)">75</button> <button class="btn" @click="change(100)">100</button> </div> <script src="<https://cdn.jsdelivr.net/npm/vue>"></script> <script> new Vue({ el: '#app', data: { num: { a: 0 }, aniMap: new Map() }, methods: { change(newNum) { this.numAni(this.num, 'a', newNum, 0); }, // obj: 数字所在对象, key: 数字属性, newVal: 新变化的值,decimal: 变化期间的小数位数, name: 不同对象出现相同key值时,可自主设定name进行区分 numAni(obj, key, newVal, decimal, name) { newVal = Number(newVal); // 处理可能是字符串的数字内容 const mapKey = name || key; if (this.aniMap.has(mapKey)) { clearInterval(this.aniMap.get(mapKey)); this.aniMap.delete(mapKey); } const diff = newVal - obj[key]; // 差值 if (diff === 0) { return; } let ch = Number((Math.abs(diff) / 11).toFixed(decimal)); // 将变化的差值分作11份,进行10次变化 ch = ch <= 1 && decimal === 0 ? 1 : ch; let count = 0; const timer = setInterval(() => { let tempNum = Number(obj[key]); if (count < 10) { count += 1; tempNum += diff < 0 ? -ch : ch; obj[key] = Number(tempNum.toFixed(decimal)); if (obj[key] === newVal) { obj[key] = newVal.toString(); clearInterval(timer); } } else { obj[key] = newVal.toString(); this.aniMap.delete(mapKey); clearInterval(timer); } }, 20); // 每单次变化耗时20ms this.aniMap.set(mapKey, timer); // 用于临时存储计时器返回值 } } }) </script> </body> </html>
注意事项
- 进行变化的数值变量,本身不能是一个单纯的基本变量,而应该存储在一个对象中。
- 此方法需要一个map来进行临时的计时器数据变量保存
- Author:游方
- URL:https://blog.ykxkykx.cn/article/91657089
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!