Почему кнопка остановки не работает в моем коде JavaScript?

// generate a random color - random hex value

const randomColor = function () {
  const hex = '0123456789ABCDEF';
  let color = '#';
  for (let i = 0; i < 6; i++) {
    color += hex[Math.floor(Math.random() * 16)];
  }
  return color;
};

let intervalId;
const startChangingColor = function () {
  intervalId = setInterval(changeBg, 3000);
  function changeBg() {
    document.body.style.backgroundColor = randomColor();
  }
};
const stopChangingColor = function () {
  clearInterval(intervalId);
};

document.querySelector('#start').addEventListener('click', startChangingColor);
document.querySelector('#stop').addEventListener('click', stopChangingColor);

В этом коде есть две кнопки: одна для запуска, другая для остановки. Когда я нажимаю кнопку «Пуск», цвет начинает меняться. Однако когда я нажимаю кнопку «Стоп», она не работает; это должно остановить изменение цвета.

Можете ли вы создать фрагмент стека, повторяющий вашу проблему? В настоящее время ваш код не вызывает описанную вами проблему. Возможно, вы дважды нажимаете «Пуск», прежде чем нажать «Стоп»?

Nick Parsons 07.10.2023 06:43

Ваша функция запуска должна проверять, запущен ли уже таймер (проверяя, не является ли идентификатор undefined), и в этом случае ничего не делать. И ваша функция остановки должна затем установить идентификатор таймера на undefined. Это позволит предотвратить несколько последовательных нажатий кнопки запуска, запускающих несколько таймеров, из которых вы можете остановить только последний.

Darryl Noakes 07.10.2023 06:55

Ваш код кажется правильным. Пожалуйста, дважды проверьте идентификаторы ваших HTML-кнопок.

iDibya.com 07.10.2023 09:14
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
74
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

проблема в том, что когда вы нажимаете кнопку «Пуск», код не проверяет, есть ли уже эффект изменения цвета фона. Если вы нажмете кнопку «Пуск» несколько раз, будет создан эффект многократного изменения цвета фона. Пока вы нажимаете «стоп», останавливается ТОЛЬКО последний.

и в функции интервала остановки вам необходимо сбросить идентификатор на undefined, его можно перезапустить снова, нажав кнопку «Пуск».

так:

// generate a random color - random hex value

const randomColor = function() {
  const hex = '0123456789ABCDEF';
  let color = '#';
  for (let i = 0; i < 6; i++) {
    color += hex[Math.floor(Math.random() * 16)];
  }
  return color;
};

let intervalId;
const startChangingColor = function() {
  // need check if already has background change effect
  if (intervalId !== undefined) {
    return;
  }

  intervalId = setInterval(changeBg, 3000);

  function changeBg() {
    document.body.style.backgroundColor = randomColor();
  }

};
const stopChangingColor = function() {
  clearInterval(intervalId);
  // reset the id to undefined
  intervalId = undefined;
};

document.querySelector('#start').addEventListener('click', startChangingColor);
document.querySelector('#stop').addEventListener('click', stopChangingColor);
<div>
  <button id = "start">start</button>
  <button id = "stop">stop</button>
</div>

Вы также можете просто вызвать clearInterval( intervalId ) перед вызовом setInterval, поскольку все, что не является идентификатором internval, в любом случае игнорируется. Таким образом, вы никогда не сможете запустить два таймера и вам не понадобятся дополнительные проверки.

somethinghere 07.10.2023 09:00
Ответ принят как подходящий

Из-за того, как работают setInterval и clearInterval, вам лучше просто вызвать stop непосредственно перед тем, как начать очищать любые интервалы активации:

const randomColor = function () {
  const hex = '0123456789ABCDEF';
  let color = '#';
  for (let i = 0; i < 6; i++) {
    color += hex[Math.floor(Math.random() * 16)];
  }
  return color;
};

let intervalId;
const startChangingColor = function () {
  stopChangingColor();
  intervalId = setInterval(changeBg, 3000);
  function changeBg() {
    document.body.style.backgroundColor = randomColor();
  }
};
const stopChangingColor = function () {
  clearInterval(intervalId);
};

document.querySelector('#start').addEventListener('click', startChangingColor);
document.querySelector('#stop').addEventListener('click', stopChangingColor);
<button id = "start">Start</button>
<button id = "stop">Stop</button>

clearInterval, как вы видите в документации здесь, неважно, что вы передаете:

Если предоставленный параметр не идентифицирует ранее установленное действие, этот метод ничего не делает.

Если это действительный идентификатор интервала, он отменит его, если это что-то еще, он будет проигнорирован, поэтому нет необходимости проверять, существует ли он или что-то в этом роде, просто очистите его с помощью переменной, которая содержит/будет хранить ваш идентификатор.

Как описано в большинстве приведенных выше ответов, одной из причин может быть то, что вы создаете несколько интервалов, последовательно нажимая кнопку «Пуск», а затем нажимая кнопку «Стоп», что фактически уничтожает только последний созданный интервал.

Я также предполагаю, что фрагмент выше, которым вы поделились, используется в каком-то библиотечном компоненте (например, компоненте React), который выполняет повторную визуализацию и теряет значение интервала при последующих повторных визуализациях. Если это так, попробуйте сохранить интервалId в состоянии.

Другие вопросы по теме