Проблема Vanila JavaScript с setInterval и clearInterval

#javascript #html

#javascript #HTML

Вопрос:

Я пытаюсь создать простую игру на умножение, используя чистый Javascript. Когда я нажимаю кнопку «Пуск», она вызывает функцию TimeCalc(). Функция TimeCalc объявляет имя переменной fullTime со значением 7 и устанавливает интервал, и после каждой секунды fullTime уменьшается на 1. когда оно уменьшается до 1, оно устанавливает значение fullTime равным 7.

Если я нажимаю на кнопку «Пуск» много раз, полное время сокращается очень быстро и беспорядочно, даже если я в начале выполнил clearInterval(). Я хочу уменьшить полное время с 7 обычным способом, даже если я нажимаю на него много раз. что происходит за сценой?

Вот мой фрагмент кода. Спасибо.

 const timeContainer = document.querySelector('.math__time');
const startBtn = document.querySelector('.math__start');

function timeCalc() {
  clearInterval(timeLeft);

  let fullTime = 7;
  timeContainer.textContent = fullTime;

  var timeLeft = setInterval(function() {
    fullTime--;
    timeContainer.textContent = fullTime;

    if (fullTime === 1) {
      fullTime = 7;
    }
  },1000);
}


startBtn.addEventListener('click', timeCalc);  
 *,
*:before,
*:after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.math {
  background: gray;
  font-family: verdana, sans-serif;
}

.math__calc {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translateY(-50%) translateX(-50%);
}

.math__num {
  margin: 15px;
  color: #fff;
  font-size: 30px;
  padding-left: 100px;
}

.math__num--wrapper {
  position: relative;
}

.math__time {
  padding: 10px;
  background: black;
  color: #fff;
  position: absolute;
  right: 20px;
  top: 20px;
  border: #fff 2px solid;
}
 

.math__start {
  position: absolute;
  left: 20px;
  top: 20px;
  border: 2px solid #fff;
  background: #333;
  color: #fff;
  padding: 10px;
}

.math__multiply--symbol {
  position: absolute;
  bottom: -10px;
  left: 10px;
  font-size: 30px;
}  
 <!DOCTYPE html>
<html>

<head>
  <title>Math</title>
  <!-- default css -->
  <link rel="stylesheet" type="text/css" href="css/main.css">

</head>

<body class="math">
  <div class="math__time">0</div>
  <button class="math__start">Start</button>
  
  <div class="math__calc">
    <div class="math__num--wrapper">
      <div class="math__num math__num--one">88</div>
      <span class="math__multiply--symbol">*</span>
      <div class="math__num math__num--two">22</div>
    </div>
    <form class="math__ans">
      <input type="text" name="answer" class="math__ans--user">
    </form>
  </div>

</body>

</html>  

Ответ №1:

Вам нужно объявить timeLeft в глобальной области видимости и изменить ее внутри функции

 const timeContainer = document.querySelector('.math__time');
const startBtn = document.querySelector('.math__start');
let timeLeft;
let fullTime;
function timeCalc() {
  clearInterval(timeLeft);

  fullTime = 7;
  timeContainer.textContent = fullTime;

  timeLeft = setInterval(function() {
    fullTime--;
    timeContainer.textContent = fullTime;

    if (fullTime === 1) {
      fullTime = 8
    }
  },1000);
}


startBtn.addEventListener('click', timeCalc);  
 *,
*:before,
*:after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.math {
  background: gray;
  font-family: verdana, sans-serif;
}

.math__calc {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translateY(-50%) translateX(-50%);
}

.math__num {
  margin: 15px;
  color: #fff;
  font-size: 30px;
  padding-left: 100px;
}

.math__num--wrapper {
  position: relative;
}

.math__time {
  padding: 10px;
  background: black;
  color: #fff;
  position: absolute;
  right: 20px;
  top: 20px;
  border: #fff 2px solid;
}
 

.math__start {
  position: absolute;
  left: 20px;
  top: 20px;
  border: 2px solid #fff;
  background: #333;
  color: #fff;
  padding: 10px;
}

.math__multiply--symbol {
  position: absolute;
  bottom: -10px;
  left: 10px;
  font-size: 30px;
}  
 <!DOCTYPE html>
<html>

<head>
  <title>Math</title>
  <!-- default css -->
  <link rel="stylesheet" type="text/css" href="css/main.css">

</head>

<body class="math">
  <div class="math__time">0</div>
  <button class="math__start">Start</button>
  
  <div class="math__calc">
    <div class="math__num--wrapper">
      <div class="math__num math__num--one">88</div>
      <span class="math__multiply--symbol">*</span>
      <div class="math__num math__num--two">22</div>
    </div>
    <form class="math__ans">
      <input type="text" name="answer" class="math__ans--user">
    </form>
  </div>

</body>

</html>  

Ответ №2:

Махир прав, единственным дополнением было бы не загрязнять ваше глобальное пространство. Создайте замыкание для хранения этих переменных. Я обновил функцию, чтобы возвращать функцию.

Проблема

Ваш clearInterval(timeLeft) на самом деле ничего не очищает. timeLeft Не определено на момент очистки.

Решение

Перемещение вашего timeleft выполняется в более широком масштабе. Вы можете либо: — Поместить его в глобальное пространство имен (не рекомендуется) — Создать область видимости вокруг функции TimeCalc.

Я реализовал второе решение, приведенное ниже. Сначала я изменил timeCalc() . Теперь timeCalc() создает функцию. Эта функция может использоваться в качестве обратного вызова для .addEventListener() .

Затем вызов этой функции в .addEventListener() вернет функцию таймера с переменными, заключенными в замыкание. Я также изменил fulltime в функции на 8, чтобы показывать 7 секунд после того, как обратный отсчет достиг 1.

 const timeContainer = document.querySelector('.math__time');
const startBtn = document.querySelector('.math__start');

function timeCalc() {
  let timeLeft = null;
  let fullTime = 7;

  return function() {      
  clearInterval(timeLeft);
  fullTime = 7;
  timeContainer.textContent = fullTime;

  timeLeft = setInterval(function() {
    fullTime--;
    timeContainer.textContent = fullTime;

    if (fullTime === 1) {
      fullTime = 8;
    }
  },1000);
}
}


startBtn.addEventListener('click', timeCalc());  
 *,
*:before,
*:after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.math {
  background: gray;
  font-family: verdana, sans-serif;
}

.math__calc {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translateY(-50%) translateX(-50%);
}

.math__num {
  margin: 15px;
  color: #fff;
  font-size: 30px;
  padding-left: 100px;
}

.math__num--wrapper {
  position: relative;
}

.math__time {
  padding: 10px;
  background: black;
  color: #fff;
  position: absolute;
  right: 20px;
  top: 20px;
  border: #fff 2px solid;
}
 

.math__start {
  position: absolute;
  left: 20px;
  top: 20px;
  border: 2px solid #fff;
  background: #333;
  color: #fff;
  padding: 10px;
}

.math__multiply--symbol {
  position: absolute;
  bottom: -10px;
  left: 10px;
  font-size: 30px;
}  
 <!DOCTYPE html>
<html>

<head>
  <title>Math</title>
  <!-- default css -->
  <link rel="stylesheet" type="text/css" href="css/main.css">

</head>

<body class="math">
  <div class="math__time">0</div>
  <button class="math__start">Start</button>
  
  <div class="math__calc">
    <div class="math__num--wrapper">
      <div class="math__num math__num--one">88</div>
      <span class="math__multiply--symbol">*</span>
      <div class="math__num math__num--two">22</div>
    </div>
    <form class="math__ans">
      <input type="text" name="answer" class="math__ans--user">
    </form>
  </div>

</body>

</html>  

Комментарии:

1. Что происходило внутри функции TimeCalc () до того, как она была решена? почему возникла эта проблема? И теперь, почему нам нужно добавлять скобки в .addEventListener во время вызова функции?