【问题标题】:How to execute setInterval at a later time in the code inside conditional statements in javascript?如何稍后在 javascript 条件语句中的代码中执行 setInterval?
【发布时间】:2023-02-02 07:54:07
【问题描述】:

我正在尝试更改我的 HTML 页面的背景颜色,如果单击按钮 id = 'button4',则每 200 毫秒使用 setInterval。当用户再次点击同一个按钮时,我希望背景颜色的改变停止。

setInterval 的代码在分配给 var x 时执行,而我想在调用“goCrazy”函数内部满足条件时执行它。那怎么办?

clearInterval 工作正常,颜色变化停止。

下面是我的代码。

var x = setInterval(() => {
    const rndInt1 = randomIntFromInterval(0, 255);
    const rndInt2 = randomIntFromInterval(0, 255);
    const rndInt3 = randomIntFromInterval(0, 255);
    document.body.style.backgroundColor = `rgb(${rndInt1}, ${rndInt2}, ${rndInt3})`;
    }, 200);

function goCrazy() {

    if (document.getElementById('button4').innerText == 'Go Crazy') {
        document.getElementById('button4').innerText = 'stop';
        x;
    }
    else {
        clearInterval(x);
        document.getElementById('button4').innerText = 'Go Crazy';
    }
}


function randomIntFromInterval(min, max) { // min and max included
    return Math.floor(Math.random() * (max - min + 1) + min)
  }

我正在尝试更改我的 HTML 页面的背景颜色,如果单击按钮 id = 'button4',则每 200 毫秒使用 setInterval。当用户再次点击同一个按钮时,我希望背景颜色的改变停止。

setInterval 的代码在分配给 var x 时执行,而我想在调用“goCrazy”函数内部满足条件时执行它。那怎么办?

clearInterval 工作正常,颜色变化停止。

下面是我的代码。

var x = setInterval(() => {
    const rndInt1 = randomIntFromInterval(0, 255);
    const rndInt2 = randomIntFromInterval(0, 255);
    const rndInt3 = randomIntFromInterval(0, 255);
    document.body.style.backgroundColor = `rgb(${rndInt1}, ${rndInt2}, ${rndInt3})`;
    }, 200);

function goCrazy() {

    if (document.getElementById('button4').innerText == 'Go Crazy') {
        document.getElementById('button4').innerText = 'stop';
        x;
    }
    else {
        clearInterval(x);
        document.getElementById('button4').innerText = 'Go Crazy';
    }
}


function randomIntFromInterval(min, max) { // min and max included
    return Math.floor(Math.random() * (max - min + 1) + min)
}

【问题讨论】:

  • 您可能让您的 setInterval 回调在后台运行并检查您将通过单击按钮翻转的全局布尔值。这里肯定有类似的问题
  • “setInterval 的代码在我将其分配给 var x 后立即执行”- 好吧,当你称呼一个函数,它里面的代码就会执行。
  • “setInterval 的代码在分配给 var x 时执行,因为我想在调用‘goCrazy’函数内部满足条件时执行它。” - 怎么了,呃,将满足条件时应执行的代码放入条件中
  • id只是一个ID。它是通话结果功能。可以从条件内的代码将其分配给范围更广的变量。这是迄今为止您得到的答案的基本共同点。那是混乱的地方吗?
  • @Fakipo ... OP 可能会检查我提供的答案的最新编辑。第二种方法从this-context aware(因此明确绑定)事件处理程序更改为this-context-free closure。顺便说一句,这两种方法都是非常好的“惯用 JavaScript”。两个示例代码都作为可执行堆栈 sn-ps 提供,因此它们都证明了它们的每个描述声称它在做什么。选择与哪个一起去是在 OP 上。

标签: javascript


【解决方案1】:

你可以将setInterval里面的代码提取到一个命名函数中,然后在goCrazy里面调用setInterval或者clearInterval

var x;

function goCrazy(){
    if (document.getElementById('button4').innerText == 'Go Crazy') {
        document.getElementById('button4').innerText = 'stop';
        x = setInterval(changeBackground, 200);
    }
    else {
        document.getElementById('button4').innerText = 'Go Crazy';
        if (x) clearInterval(x);
    } 
}

function changeBackground() {
    const rndInt1 = randomIntFromInterval(0, 255);
    const rndInt2 = randomIntFromInterval(0, 255);
    const rndInt3 = randomIntFromInterval(0, 255);
    document.body.style.backgroundColor = `rgb(${rndInt1}, ${rndInt2}, ${rndInt3})`;
}

function randomIntFromInterval(min, max) { // min and max included 
    return Math.floor(Math.random() * (max - min + 1) + min)
}

【讨论】:

  • 这工作正常。没有必要使用命名函数,我们也可以使用匿名函数。正确的部分是采用全局未定义变量,然后为其分配 setInterval 的 id 并使用相同的 id(如果存在)来清除间隔。标记为正确。
  • @Fakipo 答案有效,我投了赞成票。但我永远不会将使用全局变量称为“正确”。还有另一种方法,我将很快提供该答案。
  • @Dexygen 我同意,如果可能的话最好不要使用全局变量。我正在考虑使用闭包将 x 包装在 goCrazy 函数中来写一个答案,但是没有 HTML 代码来测试它,我想我会通过。
【解决方案2】:

OP首先需要使应该在一定时间间隔内运行的背景更改功能成为可寻址功能,例如将其实现为function statement

其次,OP 需要跟踪运行/暂停间隔。人们可以通过单个事件处理程序来实现这一点,该事件处理程序知道自己的 this 上下文,其中可以 bind 至少一个 timeId 到它,甚至可能是一些额外的与按钮相关的文本数据。

使用按钮的 'click' event-listener 注册的处理函数的实现非常简单。

根据 null 绑定 timerId 的值比较,可以检测到 'running''halted' 间隔,这使得继续清除运行间隔或开始新间隔(包括按钮的文本切换)变得容易).

function getRandomValue(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}
function setRandomBackgroundColor() {
  document.body.style.backgroundColor =
    `rgb(${getRandomValue(0, 255)},${getRandomValue(0, 255)},${getRandomValue(0, 255)})`;
}

function toggleBackgroundBehaviorFromBoundState({ currentTarget: elmBtn }) {
  let toggleState;

  if ((this.timerId ?? null) !== null) {

    clearInterval(this.timerId);

    // explicitly nullify value due to the above `null` comparison.
    this.timerId = null;

    toggleState = 'halted';
  } else {
    this.timerId = setInterval(setRandomBackgroundColor, 100);

    toggleState = 'running';
  }
  elmBtn.textContent = this?.buttonCopy?.[toggleState];
}

function main() {
  document
    .querySelector('#button4')
    .addEventListener(
      'click',
      toggleBackgroundBehaviorFromBoundState.bind({
        buttonCopy: {
          running: 'Stop',
          halted: 'Go Crazy',
        },
        timerId: null,
      })
    );
}
main();
<button id="button4">Go Crazy</button>

编辑

由于上述解决方案被称为“令人困惑和非惯用的 JavaScript”, 非常适合看起来受欢迎的 this-context-free closure-风格。

function getRandomValue(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}
function setRandomBackgroundColor() {
  document.body.style.backgroundColor =
    `rgb(${getRandomValue(0, 255)},${getRandomValue(0, 255)},${getRandomValue(0, 255)})`;
}

function enableBackgroundToggleForButton(elmBtn, btnCopy = {}) {
  function toggleBackgroundBehavior() {
    let toggleCopy;

    if (timerId !== null) {

      clearInterval(timerId);

      timerId = null;
      toggleCopy = copyHalted;
    } else {
      timerId = setInterval(setRandomBackgroundColor, 100);
      toggleCopy = copyRunning;
    }
    elmBtn.textContent = toggleCopy;
  }
  // explicitly nullify value due to the above `null` comparison.
  let timerId = null;
  const {
    halted: copyHalted,
    running: copyRunning,
  } = btnCopy;

  elmBtn.addEventListener('click', toggleBackgroundBehavior);
}

enableBackgroundToggleForButton(
  document.querySelector('#button4'),
  { halted: 'Go Crazy', running: 'Stop'},
);
<button id="button4">Go Crazy</button>

【讨论】:

  • 这些答案的投票数总体上是一团糟。这可能是由于meta effect,因为这个问题目前正在讨论here
  • @Fakipo ...最后代码不是关于“为[任何人]工作得很好”但它应该始终与方法的可理解性及其实现/代码的可读性、模块化和可维护性有关。
猜你喜欢
  • 1970-01-01
  • 2022-09-24
  • 2010-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-24
相关资源
最近更新 更多