[英]How can I implement a countup that stops at all counters simultaneously?
我已经实现了一个动画到数据目标的计数。 如何调整计数器以使所有计数器同时停止?
还是有更好的方法来实现这一点?
function animationEffect(){ const counters = document.querySelectorAll('.counter'); const speed = 2000; counters.forEach((counter) => { const updateCount = () => { const target = + counter.getAttribute('data-target'); const count = + counter.innerText; const inc = target / speed; if(count < target) { counter.innerText = Math.ceil(count + inc); setTimeout(updateCount, 1); } else { counter.innerText = target; } } updateCount(); }); }
<div class="counter" data-target="299" onmouseover="animationEffect()">0</div> <div class="counter" data-target="1299" onmouseover="animationEffect()">0</div> <div class="counter" data-target="99" onmouseover="animationEffect()">0</div>
我不知道它是否有帮助,但是当我更改此行时我得到了它: const inc = target / speed;
为此: const inc = 1/(speed / target);
并摆脱Math.ceil()
因为这个const speed = 2000;
这实际上是一个创建浮动值的步骤。 也许尝试更小的speed
值
编辑多一点调整,我们有一个没有浮动值的平滑答案>:D
function animationEffect(){ if(animationEffect.called){return null} animationEffect.called=true //these 2 lines prevent this function from being called multiple times to prevent overlapping //the code works without these lines though so remove them if u don't want them const counters = document.querySelectorAll('.counter'); const incrementConstant = 2; //the higher the number the faster the count rate, the lower the number the slower the count rate const speed = 2000; counters.forEach((counter) => { const updateCount = () => { const target = + counter.getAttribute('data-target'); counter.storedValue=counter.storedValue||counter.innerText-0; //saving a custom value in the element(the floating value) const count = + counter.storedValue; //accessing custom value(and rounding it) const inc = incrementConstant/(speed / target); //the math thanks to @Tidus if(count < target) { counter.storedValue=count+inc counter.innerText = Math.round(counter.storedValue); setTimeout(updateCount, 1); } else { counter.innerText = target; } } updateCount(); }); }
<div class="counter" data-target="299" onmouseover="animationEffect()">0</div> <div class="counter" data-target="1299" onmouseover="animationEffect()">0</div> <div class="counter" data-target="99" onmouseover="animationEffect()">0</div>
如果将此代码粘贴到代码顶部并运行,当您记录window.activeTimers
时,您将看到定义了数百个计时器。 这是因为每次调用updateCount
时,您都在为 updateCount 设置一个新计时器。 虽然您的animationEffect
function 就像您的程序的主要 function 一样,但如果您每次将鼠标悬停在您的计数器上时调用它,它将设置新的计时器,这意味着每次都更快地更新您的计数器。 总而言之,您目前根本无法控制。
对于定期调用,您应该使用setInterval 。 它需要一个 function 和一个延迟参数(还有可选参数。您可以查看文档)。 它repeatedly calls a function or executes a code snippet, with a fixed time delay between each call (From Mozilla docs)
。 它还返回一个间隔 ID,以便您以后可以取消它(这意味着我们可以控制它)。
所以在你的情况下,你应该做的第一件事就是停止对animationEffect的onmouseover调用并添加一个按钮来停止执行updateCounters。
<div class="counter" data-target="299">0</div>
<div class="counter" data-target="1299">0</div>
<div class="counter" data-target="99">0</div>
<button id="stop">Stop</button>
在分配变量counters
和speed
之后,我们可以定义一个数组来保存间隔的 ID,以便以后取消它们。
const counters = document.querySelectorAll(".counter");
const speed = 2000;
const cancelButton = document.getElementById('stop')
const countIntervals = [];
cancelButton.addEventListener('click', () => {
countIntervals.forEach(interval => clearInterval(interval))
})
如您所见,我为我们的按钮定义了一个事件侦听器。 当您单击它时,它将迭代countIntervals
中的间隔 ID 并清除这些间隔。 为简单起见,我没有实现诸如暂停和重置之类的功能,并且尽量不要过多地更改您的代码。 您可以稍后进行实验。
现在您应该做的第一件事是在 if 语句中注释或删除setTimeout
行。 然后我们将返回的区间 ID 推送到我们的数组countIntervals
:
counters.forEach((counter) => {
const updateCount = () => {
const target = +counter.getAttribute("data-target");
const count = +counter.innerText;
const inc = target / speed;
if (count < target) {
counter.innerText = Math.ceil(count + inc);
// setTimeout(updateCount, 1);
} else {
counter.innerText = target;
}
};
countIntervals.push(setInterval(updateCount, 10))
});
现在,一旦您按下Stop
按钮,您的计数器就会停止。 我忽略了速度功能,但如果您了解setInterval
,您可以轻松实现它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.