Javascript 用各种 setTimeout 来对抗
Javascript counter up with various setTimeout
我从各种来源创建了我能找到的最简单的 js 计数器。如何为每个计数器设置 不同的 setTimeout 以便它们同时结束?
更新:我已将下面的正确答案最小化,这是最终代码:
const counters = document.querySelectorAll('.counter');
const duration = 2000; // Finish in 2 seconds
const speed = 2000;
const state = {};
const max = Math.max(...[...counters]
.map(counter => +counter.dataset.target));
const tick = duration / max;
const updateCount = (counter) => {
const target = +counter.dataset.target;
const value = +counter.dataset.value;
const ratio = target / max;
const ms = Math.ceil(ratio * tick);
const incr = target / speed;
const newVal = value + incr;
if (value < target) {
counter.innerText = Math.floor(newVal);
counter.dataset.value = newVal;
setTimeout(updateCount, ms, counter);
} else {
counter.innerText = target;
counter.dataset.value = target;
}
};
counters.forEach(updateCount);
<div class="counter" data-key="1" data-value="0" data-target="1000">0</div>
<div class="counter" data-key="2" data-value="0" data-target="2000">0</div>
它是这样工作的,因为你的 setTimeout(updateCount, 100);
运行s 在 100 毫秒后。因此,当您从 0 数到 150 并且每 100 毫秒添加一个数字时,它会比数到 300 快两倍。
你可以同时结束,当你在50毫秒后将setTimeout()
更改为运行以计数到300
像这样
setTimeout(updateCount150, 100);
setTimeout(updateCount300, 50);
当然你需要相应地调整这两个功能。
尝试获取平均值,如下所示:
const counters = document.querySelectorAll('.counter');
const speed = 1;
let avg=0;
counters.forEach(counter => {
avg+=parseInt(counter.getAttribute('data-target'))
});
avg=avg/counters.length;
counters.forEach(counter => {
const updateCount = () => {
const count = +counter.innerText;
const target = +counter.getAttribute('data-target')
const inc = counter.getAttribute('data-target') / (speed * avg);
if (count < target) {
counter.innerText = count + inc;
setTimeout(updateCount, 100);
} else {
counter.innerText = target;
}
};
updateCount();
});
<div class="counter" data-target="150">0</div>
<div class="counter" data-target="300">0</div>
每个计时器必须 运行 以相对于最大时间的增加速率。
这是一个基本示例,可能还需要一些工作。我还建议使用 dataset
属性 来存储值并仅重新呈现该值(如果结果是浮点数)。
const results = document.querySelector('.results');
const counters = document.querySelectorAll('.counter');
const duration = 2000; // Finish in 2 seconds
const speed = 1000;
const state = {};
const max = Math.max(...[...counters]
.map(counter => +counter.dataset.target));
const tick = duration / max;
const updateCount = (counter) => {
const target = +counter.dataset.target;
const value = +counter.dataset.value;
const ratio = target / max;
const ms = Math.ceil(ratio * tick);
const incr = target / speed;
const newVal = value + incr;
const { dataset: { key }} = counter;
state[key] = {
...state[key],
ratio, ms, incr, value
};
results.textContent = JSON.stringify(state, null, 2);
if (value < target) {
counter.innerText = Math.floor(newVal);
counter.dataset.value = newVal;
setTimeout(updateCount, ms, counter);
} else {
counter.innerText = target;
counter.dataset.value = target;
}
};
counters.forEach(updateCount);
.results {
border: thin solid grey;
padding: 0.25em;
white-space: pre;
font-family: monospace;
}
<div class="counter" data-key="1" data-value="0" data-target="1000">0</div>
<div class="counter" data-key="2" data-value="0" data-target="2000">0</div>
<div class="counter" data-key="3" data-value="0" data-target="4000">0</div>
<div class="results"></div>
我从各种来源创建了我能找到的最简单的 js 计数器。如何为每个计数器设置 不同的 setTimeout 以便它们同时结束?
更新:我已将下面的正确答案最小化,这是最终代码:
const counters = document.querySelectorAll('.counter');
const duration = 2000; // Finish in 2 seconds
const speed = 2000;
const state = {};
const max = Math.max(...[...counters]
.map(counter => +counter.dataset.target));
const tick = duration / max;
const updateCount = (counter) => {
const target = +counter.dataset.target;
const value = +counter.dataset.value;
const ratio = target / max;
const ms = Math.ceil(ratio * tick);
const incr = target / speed;
const newVal = value + incr;
if (value < target) {
counter.innerText = Math.floor(newVal);
counter.dataset.value = newVal;
setTimeout(updateCount, ms, counter);
} else {
counter.innerText = target;
counter.dataset.value = target;
}
};
counters.forEach(updateCount);
<div class="counter" data-key="1" data-value="0" data-target="1000">0</div>
<div class="counter" data-key="2" data-value="0" data-target="2000">0</div>
它是这样工作的,因为你的 setTimeout(updateCount, 100);
运行s 在 100 毫秒后。因此,当您从 0 数到 150 并且每 100 毫秒添加一个数字时,它会比数到 300 快两倍。
你可以同时结束,当你在50毫秒后将setTimeout()
更改为运行以计数到300
像这样
setTimeout(updateCount150, 100);
setTimeout(updateCount300, 50);
当然你需要相应地调整这两个功能。
尝试获取平均值,如下所示:
const counters = document.querySelectorAll('.counter');
const speed = 1;
let avg=0;
counters.forEach(counter => {
avg+=parseInt(counter.getAttribute('data-target'))
});
avg=avg/counters.length;
counters.forEach(counter => {
const updateCount = () => {
const count = +counter.innerText;
const target = +counter.getAttribute('data-target')
const inc = counter.getAttribute('data-target') / (speed * avg);
if (count < target) {
counter.innerText = count + inc;
setTimeout(updateCount, 100);
} else {
counter.innerText = target;
}
};
updateCount();
});
<div class="counter" data-target="150">0</div>
<div class="counter" data-target="300">0</div>
每个计时器必须 运行 以相对于最大时间的增加速率。
这是一个基本示例,可能还需要一些工作。我还建议使用 dataset
属性 来存储值并仅重新呈现该值(如果结果是浮点数)。
const results = document.querySelector('.results');
const counters = document.querySelectorAll('.counter');
const duration = 2000; // Finish in 2 seconds
const speed = 1000;
const state = {};
const max = Math.max(...[...counters]
.map(counter => +counter.dataset.target));
const tick = duration / max;
const updateCount = (counter) => {
const target = +counter.dataset.target;
const value = +counter.dataset.value;
const ratio = target / max;
const ms = Math.ceil(ratio * tick);
const incr = target / speed;
const newVal = value + incr;
const { dataset: { key }} = counter;
state[key] = {
...state[key],
ratio, ms, incr, value
};
results.textContent = JSON.stringify(state, null, 2);
if (value < target) {
counter.innerText = Math.floor(newVal);
counter.dataset.value = newVal;
setTimeout(updateCount, ms, counter);
} else {
counter.innerText = target;
counter.dataset.value = target;
}
};
counters.forEach(updateCount);
.results {
border: thin solid grey;
padding: 0.25em;
white-space: pre;
font-family: monospace;
}
<div class="counter" data-key="1" data-value="0" data-target="1000">0</div>
<div class="counter" data-key="2" data-value="0" data-target="2000">0</div>
<div class="counter" data-key="3" data-value="0" data-target="4000">0</div>
<div class="results"></div>