Главная » Таймер обратного отсчёта для сайта. Реализация на чистом JS.

Таймер обратного отсчёта для сайта. Реализация на чистом JS.


06.05.2021, 10:42
Базовая структура таймера

Таймер - это блок, разделённый на отдельные секции (дни, часы, минуты, секунды). Данный блок возьмём за основу как родительский:

Код

<div class="timer">
  /* здесь будут секции (счётчики) таймера */
</div>

Каждый из счётчиков - отдельный блок с классом timer__block, внутри которого span с уникальным id (в нём будут выводиться показания счётчика) и пояснительный текст под счётчиком

Код

  <div class="timer">

  <div class="timer__block">
  <span id="days">0</span>
  дней
  </div>

  <div class="timer__block">
  <span id="hours">0</span>
  часов
  </div>

  <div class="timer__block">
  <span id="minutes">0</span>
  минут
  </div>

  <div class="timer__block">
  <span id="seconds">0</span>
  секунд
  </div>

  </div>


Так выглядит таймер, оформленный минимально css-стилями



Код

.promotion__timer .timer{
  margin-top:50px;
  padding-left:50px;
  display:flex;
  justify-content:space-between;
  align-items:center
}
.promotion__timer .timer__block{
  width:120px;
  height:120px;
  background: #bdc3c7;
  color: #666666;
  font-size:16px;
  font-weight:400;
  text-align:center;
  border-radius:5px;
  box-shadow: 6px -6px 4px 1px rgba(52, 73, 94, .1);
}
.promotion__timer .timer__block span{
  display:block;
  margin-top:20px;
  margin-bottom:5px;
  font-size:46px;
  font-weight:700;
  text-shadow: #ffffff 0px 0 5px;
}


Пишем логику работы таймера

Определяем дату дедлайна и сохраняем её в переменную:

Код

const deadline = '2021-05-30'; // => 30-го мая счётчик должен остановиться

Пишем функцию, определяющую разницу между дедлайном и текущим временем, в качестве аргумента она будет принимать deadlineendtime будет передаваться дата в формате строки '2021-05-30')

Код

function getTimeRemaining(endtime) {
   
}

Далее мы будем использовать метод Date.parse(), чтобы из строки получить количество миллисекунд, в переменную t сохранится разница (в миллисекундах) между дедлайном и текущим временем:

Код

function getTimeRemaining(endtime) {
  const t = Date.parse(endtime) - Date.parse(new Date());
}

Значение миллисекунд, сохранённое в переменной t, теперь можно разобрать на дни, часы, минуты и секунды. При этом используем метод Math.floor() для округления значений до ближайшего меньшего целого.

Начинаем с дней:

Код

const deadline = '2021-05-30';

function getTimeRemaining(endtime) {
  const t = Date.parse(endtime) - Date.parse(new Date()),
  days = Math.floor(t / 1000 / 60 / 60 / 24); /* => получили целое число дней */
}

Логика вычислений тут такова:

а) разделив количество миллисекунд из переменной t на 1000, мы получим кличество секунд (так как в 1 секунде 1000 миллисекунд)
б) количество секунд делим на 60, получаем минуты (так как в 1 минуте 60 секунд)
в) количество минут делим на 60, получаем часы (в одном часе 60 минут)
г) количество часов делим на 24, получаем дни (в сутках 24 часа)

Таким образом мы получили количество дней для первого счётчика таймера.

Получаем количество часов, оставшихся до дедлайна

Код

function getTimeRemaining(endtime) {
  const t = Date.parse(endtime) - Date.parse(new Date()),
  days = Math.floor(t / 1000 / 60 / 60 / 24),
  hours = Math.floor((t / 1000 / 60 / 60) % 24); /* => получили количество часов до дедлайна */
}

Разбираем логику этих вычислений:

а) разделив количество миллисекунд из переменной t на 1000, мы получим кличество секунд (так как в 1 секунде 1000 миллисекунд)
б) количество секунд делим на 60, получаем минуты (так как в 1 минуте 60 секунд)
в) количество минут делим на 60, получаем часы (в одном часе 60 минут)
г) к полученным часам мы применяем оператор % ( остаток от деления)

Для чего применять оператор %?

Пример: мы получили количество часов 54

а) зная, что в сутках 24 часа, мы понимаем, что полученное количество часов содержит в себе какое-то количество целых дней и плюс ещё сколько-то отдельных часов
б) применяя оператор остатка от деления, мы вычленяем эти отдельные часы, при этом отбрасывая целые дни

Код
54 % 24 => 6

По аналогии получаем значения минут и секунд:

Код

const deadline = '2021-05-30';

function getTimeRemaining(endtime) {
  const t = Date.parse(endtime) - Date.parse(new Date()),
  days = Math.floor(t / 1000 / 60 / 60 / 24),
  hours = Math.floor((t / 1000 / 60 / 60) % 24),
  minutes = Math.floor((t / 1000 / 60) % 60),
  seconds = Math.floor((t / 1000) % 60);
}


Работа оператора остатка от деления на примере

Чтобы иметь возможность использовать полученные данные вне функции, возвращаем их в виде объекта:

Код

const deadline = '2021-05-30';

function getTimeRemaining(endtime) {
  const t = Date.parse(endtime) - Date.parse(new Date()),
  days = Math.floor(t / 1000 / 60 / 60 / 24),
  hours = Math.floor((t / 1000 / 60 / 60) % 24),
  minutes = Math.floor((t / 1000 / 60) % 60),
  seconds = Math.floor((t / 1000) % 60);

  return {
  'total': t,
  'days': days,
  'hours': hours,
  'minutes': minutes,
  'seconds': seconds
  };
}

Пишем функцию, которая будет устанавливать значения счётчиков на страницу сайта:

Код

  function setClock(selector, endtime) {

  }

В качестве аргументов она будет принимать родительский блок таймера и дедлайн.

Определяем необходимые элементы таймера:

Код

  function setClock(selector, endtime) {
  const timer = document.querySelector(selector),
  days = timer.querySelector('#days'),
  hours = timer.querySelector('#hours'),
  minutes = timer.querySelector('#minutes'),
  seconds = timer.querySelector('#seconds');  
  }

Внутри функции setClock() пишем функцию обновления счётчиков таймера, эта функция будет обновлять таймер каждую секунду.

Для начала внутри неё мы получаем оставшееся время до дедлайна:

Код

  function updateClock() {
  const t = getTimeRemaining(endtime); /* получаем оставшееся до дедлайна время */  
  }

Результатом работы функции getTimeRemaining() у нас будет объект, используя данные которого, помещаем данные в счётчики таймера на странице:

Код

  function updateClock() {
  const t = getTimeRemaining(endtime); /* получаем оставшееся до дедлайна время */

  days.innerHTML = t.days;
  hours.innerHTML = t.hours;
  minutes.innerHTML = t.minutes;
  seconds.innerHTML = t.seconds;
  }

В функцию setClock() добавляем переменную timeInterval, в которую сохраняем вызов функции updateClock() каждую секунду:

Код

  function setClock(selector, endtime) {
  const timer = document.querySelector(selector),
  days = timer.querySelector('#days'),
  hours = timer.querySelector('#hours'),
  minutes = timer.querySelector('#minutes'),
  seconds = timer.querySelector('#seconds'),
  timeInterval = setInterval(updateClock, 1000);

  function updateClock() {
  const t = getTimeRemaining(endtime); /* получаем оставшееся до дедлайна время */

  days.innerHTML = t.days;
  hours.innerHTML = t.hours;
  minutes.innerHTML = t.minutes;
  seconds.innerHTML = t.seconds;
  }
  }

Внутри функции updateClock() мы будем обнулять setInterval(), проверяя условие:

Код

  if (t.total <= 0) {
  clearInterval(timeInterval);
  }  

Вызываем функцию setClock(), передавая ей в качестве аргументов родительский блок и время дедлайна

Код

setClock('.timer', deadline);

Исправляем баги таймера

В том коде, что есть на данный момент, два недочёта:

а) при перезагрузке страницы в счётчиках на секунду сначала выводятся дефолтные нули, а потом правильные значения (из-за того, что setInterval() запускает первый раз функцию updateClock() спустя 1 секунду)

б) к значениям счётчиков, меньшим 10, неплохо бы добавить впереди ноль, чтобы во всех счётчиках были двухразрядные показатели


Чтобы счётчики таймера выглядели единообразно, нужно их все привести к двойному разряду цифр

Решением первой проблемы будет вызов функции updateClock() вручную один раз, тем самым мы скомпенсируем задержку её вызова из-за setInterval()

Код

window.addEventListener('DOMContentLoaded', function () {

  const deadline = '2021-05-30';

  function getTimeRemaining(endtime) {
  const t = Date.parse(endtime) - Date.parse(new Date()),
  days = Math.floor(t / 1000 / 60 / 60 / 24),
  hours = Math.floor((t / 1000 / 60 / 60) % 24),
  minutes = Math.floor((t / 1000 / 60) % 60),
  seconds = Math.floor((t / 1000) % 60);

  return {
  'total': t,
  'days': days,
  'hours': hours,
  'minutes': minutes,
  'seconds': seconds
  };
  }

  function setClock(selector, endtime) {
  const timer = document.querySelector(selector),
  days = timer.querySelector('#days'),
  hours = timer.querySelector('#hours'),
  minutes = timer.querySelector('#minutes'),
  seconds = timer.querySelector('#seconds'),
  timeInterval = setInterval(updateClock, 1000);

  updateClock(); /* компенсируем задержку вызова этой функции в методе setInterval() */

  function updateClock() {
  const t = getTimeRemaining(endtime); /* получаем оставшееся до дедлайна время */

  days.innerHTML = t.days;
  hours.innerHTML = t.hours;
  minutes.innerHTML = t.minutes;
  seconds.innerHTML = t.seconds;

  if (t.total <= 0) {
  clearInterval(timeInterval);
  }
  }
  }

  setClock('.timer', deadline);
});

Для решения второй проблемы прописываем какую-то функцию, которая будет проверять число, и если оно будет меньше 10 (одинарный разряд числа), то к числу впереди будет добавляться ноль:

Код

  function getZero(num) {
  if (num >= 0 && num < 10) {
  return `0${num}`;
  } else {
  return num;
  }
  }

И теперь эту функцию используем, пердавая в неё в качестве аргумента значения, полученные из объекта:

Было:

Код

  days.innerHTML = t.days;
  hours.innerHTML = t.hours;
  minutes.innerHTML = t.minutes;
  seconds.innerHTML = t.seconds;

Стало:

Код

  days.innerHTML = getZero(t.days);
  hours.innerHTML = getZero(t.hours);
  minutes.innerHTML = getZero(t.minutes);
  seconds.innerHTML = getZero(t.seconds);

Полный код скрипта таймера:

Код

window.addEventListener('DOMContentLoaded', function () {

  const deadline = '2021-05-30';

  function getTimeRemaining(endtime) {
  const t = Date.parse(endtime) - Date.parse(new Date()),
  days = Math.floor(t / 1000 / 60 / 60 / 24),
  hours = Math.floor((t / 1000 / 60 / 60) % 24),
  minutes = Math.floor((t / 1000 / 60) % 60),
  seconds = Math.floor((t / 1000) % 60);

  return {
  'total': t,
  'days': days,
  'hours': hours,
  'minutes': minutes,
  'seconds': seconds
  };
  }

  function getZero(num) {
  if (num >= 0 && num < 10) {
  return `0${num}`;
  } else {
  return num;
  }
  }

  function setClock(selector, endtime) {
  const timer = document.querySelector(selector),
  days = timer.querySelector('#days'),
  hours = timer.querySelector('#hours'),
  minutes = timer.querySelector('#minutes'),
  seconds = timer.querySelector('#seconds'),
  timeInterval = setInterval(updateClock, 1000);

  updateClock(); /* компенсируем задержку вызова этой функции в методе setInterval() */

  function updateClock() {
  const t = getTimeRemaining(endtime); /* получаем оставшееся до дедлайна время */

  days.innerHTML = getZero(t.days);
  hours.innerHTML = getZero(t.hours);
  minutes.innerHTML = getZero(t.minutes);
  seconds.innerHTML = getZero(t.seconds);

  if (t.total <= 0) {
  clearInterval(timeInterval);
  }

  }
  }

  setClock('.timer', deadline);
});

КОММЕНТАРИИ (1)

Пример реализации таймера по коду выше

ТЕГИ МАТЕРИАЛА
Math.floor(), Date.parse(), js таймер
РЕЙТИНГ МАТЕРИАЛА (0.0 / 0)