如何在 JavaScript 中添加一个显示上升的“动画”数字?

问题描述 投票:0回答:2

所以,我正在尝试用 HTML 和 JavaScript 制作一个随机数生成器。我希望它有一个东西,在它达到随机数之前它会增加一个,所以它有某种“动画”,但我不能让它工作。这是我的代码:

document.getElementById("numbergenerator").onclick = generateNumber;

function generateNumber() {
    numbervalue = Math.floor(Math.random() * 1001);
  for(var i = 0; i < numbervalue; i++) {
    setTimeout(goUpThing(i), 10);
  }
  document.getElementById("numberdisplay").innerHTML = numbervalue;
}

function goUpThing(number) {
    document.getElementById("numberdisplay").innerHTML = number;
}
<html>
  <body>
    <h1>
      <em>random stuff</em>
    </h1>
    <hr>
    <h2 id="numberdisplay">
      there is no number yet
    </h2>
    <div>
    <button id="numbergenerator" type="button">
      generate a random number
    </button>
    </div>
  </body>
</html>

有人可以帮帮我吗?顺便说一句,我正在使用 JSFiddle 来运行我的代码。

javascript html
2个回答
5
投票

您可以使用

setInterval()
clearInterval()

setInterval
允许函数以
ms
中设置的时间间隔运行(本例中为 1)。 它被分配给一个名为
interval
的变量以供以后参考。 内部函数在每个时间间隔递增
counter
,直到满足条件 -
counter
等于随机
numbervalue
。然后将先前的变量
interval
传递给
clearInterval
并停止运行内部函数

document.getElementById("numbergenerator").onclick = generateNumber;

function generateNumber() {
  let numbervalue = Math.floor(Math.random() * 1001);
  let counter = 0;
  let interval = setInterval(() => {
    document.getElementById("numberdisplay").innerHTML = counter;
    counter++;
    if (counter === numbervalue) {
      clearInterval(interval);
    }
  }, 1);
}
  <body>
    <h1>
      <em>random stuff</em>
    </h1>
    <hr>
    <h2 id="numberdisplay">
      there is no number yet
    </h2>
    <div>
    <button id="numbergenerator" type="button">
      generate a random number
    </button>
    </div>
  </body>


0
投票

有几种方法可以实现这一点。

  • 您可以使用
    async/await
    setTimeout
    requestAnimationFrame
    组合来等待显示下一个数字。 (示例 1 和 2)
  • 您可以一次启动多个超时,每个超时取决于生成的数量。 (例子 3)
  • 您可以使用带有结束条件的间隔。 (例 4)
  • 您可以使用带有结束条件的
    requestAnimationFrame()
    循环。 (例 5)
  • 您可以使用
    setTimeout
    requestAnimationFrame
    生成承诺链以等待显示下一个数字。 (例 6)

可能还有更多。

所有示例都显示一个从 1-1000 的随机数。

示例的执行时间可能会有所不同。如果每个数字必须至少显示一次,则应使用

requestAnimationFrame()
。它可能比 10 毫秒的间隔或超时“慢”,因为它基本上取决于屏幕的刷新率。在 60hz 上,它类似于 17ms 的间隔(1000 / 60 = 16.666~),而 setTimeout 或 setInterval 回调可能会在同一帧多次调用。

示例 3-6 也适用于旧版浏览器不支持异步/等待,如果需要,您可能还需要将箭头功能更改为经典功能。如果不支持Promise,示例 6 可能还需要一个 Promise polyfill。

例一

生成一个从1到1000的随机数,在循环内等待超时结束,然后脚本继续。

// example 1 using async/await w/ setTimeout on a promise callback
button.onclick = async () => {
  button.disabled = true;
  let rand = Math.ceil(Math.random() * 1000);
  for (let i = 1; i <= rand; i++) {
    output.innerText = i;
    /**
     * You could also define a sleep function and await it
     *   function sleep(t) { return new Promise(r => setTimeout(r,t); }
     *
     *   await sleep(10);
     */
    await new Promise(resolve => setTimeout(resolve, 10));
  }
  button.disabled = false;
}
<h4>Example 1: async function w/ await setTimeout</h4>
<p id="output">click the button</p>
<button id="button" type="button">launch</button>

例二

类似于#1,它只是等待下一帧。

// example 2 using async/await w/ requestAnimationFrame on a promise
// this example will decrease the speed hardly,
// if you switch to another tab while it's counting up
button.onclick = async () => {
  button.disabled = true;
  let rand = Math.ceil(Math.random() * 1000);
  for (let i = 1; i <= rand; i++) {
    output.innerText = i;
    await new Promise(resolve => requestAnimationFrame(resolve));
  }
  button.disabled = false;
}
<h4>Example 2: async function w/ await requestAnimationFrame</h4>
<p id="output">click the button</p>
<button id="button" type="button">launch</button>

示例 3

一次启动多个超时,每个超时延迟

10 * numberToDisplay
ms。

// example 3 starting N setTimeout calls at once
button.onclick = () => {
  button.disabled = true;
  let rand = Math.ceil(Math.random() * 1000);
  for (let i = 1; i <= rand; i++) {
    setTimeout((value) => {
      output.innerText = value;
      // pass current value of i to the function in the setTimeout call
    }, i * 10, i);
  }
  setTimeout(() => {
    button.disabled = false;
  }, 10 * rand + 10)
}
<h4>Example 3: starting N setTimeout requests at the same time</h4>
<p id="output">click the button</p>
<button id="button" type="button">launch</button>

示例 4

使用带有结束条件的 setInterval。

// example 4 setInterval with end condition
button.onclick = () => {
  button.disabled = true;
  const rand = Math.ceil(Math.random() * 1000);
  const interval = setInterval((obj) => {
    output.innerText = ++obj.v;
    if (obj.v == rand) {
       clearInterval(interval);
       button.disabled = false;
    }
    // passing an object, to keep the reference for increment,
    // you could also define the counter outside the function 
    // using let or var and increase it's value on every tick
  }, 10, { v: 0 })
}
<h4>Example 4: setInterval with end condition</h4>
<p id="output">click the button</p>
<button id="button" type="button">launch</button>

示例 5

类似于#4,但是这个使用带有结束条件的requestAnimationFrame,每次调用函数时都会增加传递的值,从0开始,显示的第一个数字是1。

// example 5: requestAnimationFrame-loop with end condition
// like example 2, this will decrease the speed hardly,
// if you switch to another tab while it's running
button.onclick = () => {
  button.disabled = true;
  const rand = Math.ceil(Math.random() * 1000);
  (function count(i) {
    output.innerText = ++i;
    if (i == rand) {
      button.disabled = false;
    } else {      
      requestAnimationFrame(() => count(i));
    }
  })(0) // invoke the function directly to start
}
<h4>Example 5: requestAnimationFrame-loop with end condition</h4>
<p id="output">click the button</p>
<button id="button" type="button">launch</button>

示例 6

这与 #1 和 #2 的工作方式类似,并确保仅在承诺履行后才显示下一个数字。

// example 6: Promise-Chain
button.onclick = () => {
  button.disabled = true;
  let rand = Math.ceil(Math.random() * 1000);
  let prom = Promise.resolve(0);
  while (rand--) {
    prom = prom.then(v => {
      output.innerText = ++v;
      return new Promise(res => setTimeout(res, 10, v))
    });
  }
  prom.finally(() => {
    button.disabled = false;
  });
}

buttonRAF.onclick = () => {
  buttonRAF.disabled = true;
  let rand = Math.ceil(Math.random() * 1000);
  let prom = Promise.resolve(0);
  while (rand--) {
    prom = prom.then(v => {
      outputRAF.innerText = ++v;
      return new Promise(res => requestAnimationFrame(() => res(v)))
    });
  }
  prom.finally(() => {
    buttonRAF.disabled = false;
  });
}
<h4>
  Example 6: Promise-Chain
  <button onclick="button.click(), buttonRAF.click()">both</button>
</h4>
<p id="output">click the button</p>
<button id="button">launch (setTimeout)</button>

<p id="outputRAF">click the button</p>
<button id="buttonRAF">launch (requestAnimationFrame)</button>

© www.soinside.com 2019 - 2024. All rights reserved.