Таймер обратного отсчёта на чистом JavaScript

Александр Мальцев
Александр Мальцев
9,4K
12
Таймер обратного отсчёта на чистом JavaScript
Содержание:
  1. Демо таймера обратного отсчёта
  2. Подключение и настройка таймера
  3. Структура кода JavaScript
  4. Скрипт для создания нескольких таймеров отчета на странице
  5. Комментарии

В этой статье рассмотрим таймер обратного отсчета, построенный на чистом CSS и JavaScript. Он написан с использованием минимального количества кода без использования jQuery и каких-либо других сторонних библиотек.

Таймеры обратного отсчёта могут использоваться на сайтах для различных целей. Но в большинстве случаев они применяются для отображения времени, которое осталось до наступления какого-то крупного события: запуска нового продукта, рекламной акции, начала распродажи и т.д.

Демо таймера обратного отсчёта

Простой таймер обратного отсчета с днями, часами, минутами и секундами. Очень легко настраивается. Создан на чистом CSS и Javascript (без зависимостей).

Простой таймер обратного отсчета с днями, часами, минутами и секундами на чистом CSS и JavaScript

Посмотреть

Подключение и настройка таймера

1. Вставить в нужное место страницы html-разметку таймера:

<div class="timer">
  <div class="timer__items">
    <div class="timer__item timer__days">00</div>
    <div class="timer__item timer__hours">00</div>
    <div class="timer__item timer__minutes">00</div>
    <div class="timer__item timer__seconds">00</div>
  </div>
</div>

Таймер обратного отсчета отображает четыре числа: дни, часы, минуты и секунды. Каждое число находится в элементе <div>. Первый класс (timer__item) используется для стилизации элемента, а второй - для таргетинга в JavaScript.

2. Добавить стили (базовое оформление):

.timer__items {
  display: flex;
  font-size: 48px;
}
.timer__item {
  position: relative;
  min-width: 60px;
  margin-left: 10px;
  margin-right: 10px;
  padding-bottom: 15px;
  text-align: center;
}
.timer__item::before {
  content: attr(data-title);
  display: block;
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
  font-size: 14px;
}
.timer__item:not(:last-child)::after {
  content: ':';
  position: absolute;
  right: -15px;
}

Стилизовать таймер обратного отсчета можно так как вы этого хотите.

Вышеприведённый CSS использует flexbox. Знак «:» и текст под каждым компонентом даты выводиться на страницу с помощью псевдоэлементов.

3. Добавить JavaScript:

document.addEventListener('DOMContentLoaded', function() {
  // конечная дата, например 1 июля 2021
  const deadline = new Date(2021, 06, 01);
  // id таймера
  let timerId = null;
  // склонение числительных
  function declensionNum(num, words) {
    return words[(num % 100 > 4 && num % 100 < 20) ? 2 : [2, 0, 1, 1, 1, 2][(num % 10 < 5) ? num % 10 : 5]];
  }
  // вычисляем разницу дат и устанавливаем оставшееся времени в качестве содержимого элементов
  function countdownTimer() {
    const diff = deadline - new Date();
    if (diff <= 0) {
      clearInterval(timerId);
    }
    const days = diff > 0 ? Math.floor(diff / 1000 / 60 / 60 / 24) : 0;
    const hours = diff > 0 ? Math.floor(diff / 1000 / 60 / 60) % 24 : 0;
    const minutes = diff > 0 ? Math.floor(diff / 1000 / 60) % 60 : 0;
    const seconds = diff > 0 ? Math.floor(diff / 1000) % 60 : 0;
    $days.textContent = days < 10 ? '0' + days : days;
    $hours.textContent = hours < 10 ? '0' + hours : hours;
    $minutes.textContent = minutes < 10 ? '0' + minutes : minutes;
    $seconds.textContent = seconds < 10 ? '0' + seconds : seconds;
    $days.dataset.title = declensionNum(days, ['день', 'дня', 'дней']);
    $hours.dataset.title = declensionNum(hours, ['час', 'часа', 'часов']);
    $minutes.dataset.title = declensionNum(minutes, ['минута', 'минуты', 'минут']);
    $seconds.dataset.title = declensionNum(seconds, ['секунда', 'секунды', 'секунд']);
  }
  // получаем элементы, содержащие компоненты даты
  const $days = document.querySelector('.timer__days');
  const $hours = document.querySelector('.timer__hours');
  const $minutes = document.querySelector('.timer__minutes');
  const $seconds = document.querySelector('.timer__seconds');
  // вызываем функцию countdownTimer
  countdownTimer();
  // вызываем функцию countdownTimer каждую секунду
  timerId = setInterval(countdownTimer, 1000);
});

4. Установить дату окончания. Например, до 1 июля 2021:

// конечная дата
const deadline = new Date(2021, 06, 01);

Структура кода JavaScript

Основную часть кода занимает функция countdownTimer:

function countdownTimer() {
  // ...
}

Эта функция выполняет расчёт оставшегося времени и обновляет содержимое элементов .timer__item на странице.

Расчёт оставшегося времени осуществляется посредством вычитания текущей даты из конечной:

// new Date() - текущая дата и время
const diff = deadline - new Date();

Вычисление оставшегося количества дней, часов, минут и секунд выполняется следующим образом:

const days = diff > 0 ? Math.floor(diff / 1000 / 60 / 60 / 24) : 0;
const hours = diff > 0 ? Math.floor(diff / 1000 / 60 / 60) % 24 : 0;
const minutes = diff > 0 ? Math.floor(diff / 1000 / 60) % 60 : 0;
const seconds = diff > 0 ? Math.floor(diff / 1000) % 60 : 0;

Встроенная функция Math.floor используется для округления числа до ближайшего целого (посредством отбрасывания дробной части).

Вывод оставшегося времени на страницу:

$days.textContent = days < 10 ? '0' + days : days;
$hours.textContent = hours < 10 ? '0' + hours : hours;
$minutes.textContent = minutes < 10 ? '0' + minutes : minutes;
$seconds.textContent = seconds < 10 ? '0' + seconds : seconds;
$days.dataset.title = declensionNum(days, ['день', 'дня', 'дней']);
$hours.dataset.title = declensionNum(hours, ['час', 'часа', 'часов']);
$minutes.dataset.title = declensionNum(minutes, ['минута', 'минуты', 'минут']);
$seconds.dataset.title = declensionNum(seconds, ['секунда', 'секунды', 'секунд']);

Переменные $days, $hours, $minutes, $seconds содержат элементы (таргеты), в которые выводятся компоненты времени.

Изменение содержимого элементов выполняется через textContent. Если значение меньше 10, то к нему добавляется символ «0».

Получение элементов (выполняется с помощью querySelector):

// получаем элементы, содержащие компоненты даты
const $days = document.querySelector('.timer__days');
const $hours = document.querySelector('.timer__hours');
const $minutes = document.querySelector('.timer__minutes');
const $seconds = document.querySelector('.timer__seconds');

Функция declensionNum используется для склонения числительных:

// склонение числительных
function declensionNum(num, words) {
  return words[(num % 100 > 4 && num % 100 < 20) ? 2 : [2, 0, 1, 1, 1, 2][(num % 10 < 5) ? num % 10 : 5]];
}

Для постоянного вычисления оставшегося времени и вывода его на страницу используется setInterval.

Хранение идентификатора таймера осуществляется в переменной timerId:

// id таймера
let timerId = null;

Использование setInterval для запуска функции countdownTimer каждую секунду:

// вызываем функцию countdownTimer каждую 1 секунду
timerId = setInterval(countdownTimer, 1000);

Остановка таймера по истечении времени выполняется в функции countdownTimer:

function countdownTimer() {
  ...
  if (diff <= 0) {
    // останавливаем таймер timerId
    clearInterval(timerId);
  }
  ...
}

Скрипт для создания нескольких таймеров отчета на странице

Скрипт, написанный с использованием классов, который можно использовать для создания нескольких таймеров отчета на странице:

// класс для создание таймера обратного отсчета
class CountdownTimer {
  constructor(deadline, cbChange, cbComplete) {
    this._deadline = deadline;
    this._cbChange = cbChange;
    this._cbComplete = cbComplete;
    this._timerId = null;
    this._out = {
      days: '', hours: '', minutes: '', seconds: '',
      daysTitle: '', hoursTitle: '', minutesTitle: '', secondsTitle: ''
    };
    this._start();
  }
  static declensionNum(num, words) => {
    return words[(num % 100 > 4 && num % 100 < 20) ? 2 : [2, 0, 1, 1, 1, 2][(num % 10 < 5) ? num % 10 : 5]];
  }
  _start() {
    this._calc();
    this._timerId = setInterval(this._calc.bind(this), 1000);
  }
  _calc() {
    const diff = this._deadline - new Date();
    const days = diff > 0 ? Math.floor(diff / 1000 / 60 / 60 / 24) : 0;
    const hours = diff > 0 ? Math.floor(diff / 1000 / 60 / 60) % 24 : 0;
    const minutes = diff > 0 ? Math.floor(diff / 1000 / 60) % 60 : 0;
    const seconds = diff > 0 ? Math.floor(diff / 1000) % 60 : 0;
    this._out.days = days < 10 ? '0' + days : days;
    this._out.hours = hours < 10 ? '0' + hours : hours;
    this._out.minutes = minutes < 10 ? '0' + minutes : minutes;
    this._out.seconds = seconds < 10 ? '0' + seconds : seconds;
    this._out.daysTitle = CountdownTimer.declensionNum(days, ['день', 'дня', 'дней']);
    this._out.hoursTitle = CountdownTimer.declensionNum(hours, ['час', 'часа', 'часов']);
    this._out.minutesTitle = CountdownTimer.declensionNum(minutes, ['минута', 'минуты', 'минут']);
    this._out.secondsTitle = CountdownTimer.declensionNum(seconds, ['секунда', 'секунды', 'секунд']);
    this._cbChange ? this._cbChange(this._out) : null;
    if (diff <= 0) {
      clearInterval(this._timerId);
      this._cbComplete ? this._cbComplete() : null;
    }
  }
}

Пример использования класса CountdownTimer() для создания таймера на странице:

// 1. Получим элементы в которые нужно вывести оставшееся количество дней, часов, минут и секунд
const elDays1 = document.querySelector('.timer-1 .timer__days');
const elHours1 = document.querySelector('.timer-1 .timer__hours');
const elMinutes1 = document.querySelector('.timer-1 .timer__minutes');
const elSeconds1 = document.querySelector('.timer-1 .timer__seconds');

// 2. Установим время, например, на одну минуту от текущей даты
const deadline1 = new Date(Date.now() + (60 * 1000 + 999));

// 3. Создадим новый объект, используя new CountdownTimer()
new CountdownTimer(deadline1, (timer) => {
  elDays1.textContent = timer.days;
  elHours1.textContent = timer.hours;
  elMinutes1.textContent = timer.minutes;
  elSeconds1.textContent = timer.seconds;
  elDays1.dataset.title = timer.daysTitle;
  elHours1.dataset.title = timer.hoursTitle;
  elMinutes1.dataset.title = timer.minutesTitle;
  elSeconds1.dataset.title = timer.secondsTitle;
}, () => {
  document.querySelector('.timer-1 .timer__result').textContent = 'Таймер завершился!';
});

В new CountdownTimer() необходимо передать следующие аргументы:

  • конечную дату в формате Date;
  • функцию, которую нужно выполнять каждую секунду (её, например, можно использовать для обновления содержимого элементов, которые используются для отображения оставшегося времени);
  • при необходимости функцию, которую нужно выполнить после завершения таймера.

HTML код первого таймера:

<div class="timer timer-1">
  <div class="timer__items">
    <div class="timer__item timer__days">00</div>
    <div class="timer__item timer__hours">00</div>
    <div class="timer__item timer__minutes">00</div>
    <div class="timer__item timer__seconds">00</div>
  </div>
  <div class="timer__result"></div>
</div>

Инициализация остальных таймеров на странице с помощью new CountdownTimer() выполняется аналогично.

Пример страницы, на которой имеется несколько таймеров обратного отсчёта:

Несколько таймеров обратного отсчета на одной странице

Посмотреть

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

  1. Вячеслав
    Вячеслав
    27.01.2022, 19:49
    А как помимо конечной даты добавить конечное время. Например до начала какого-то события (концерта, турнира, лекции и т.п.)?
    1. Вячеслав
      Вячеслав
      27.01.2022, 20:40
      Сам разобрался. Может кому поможет
      // конечная дата 28.01.22 12.00
      const deadline = (function(y, m, d, h) { return new Date(y, m-1, d, h); })(2022, 01, 28, 12);
    2. Сергей Плахотин
      Сергей Плахотин
      30.12.2021, 22:00
      Добрый день, подскажите как можно модернизировать скрипт, что бы была возможность реализовывать множество таймеров на одной странице и с разными deadline. Заранее спасибо. Как на картинке:
      1. Александр Мальцев
        Александр Мальцев
        31.12.2021, 09:12
        Привет! Переписал скрипт на классах и добавил его в статью. Его можно использовать для создания множества таймеров на странице.
        Пример вызова:
        // deadline - конечная дата
        // cb1 - функция обратного вызова, которая будет вызываться каждую секунду и которую можно использовать для обновления содержимого элементов, содержащих оставшееся время
        // cb2 - функция обратного вызова, которая будет запущена после завершения таймера 
        new CountdownTimer(deadline, cb1, cb2);
        1. Сергей Плахотин
          Сергей Плахотин
          31.12.2021, 14:16
          Спасибо огромное! С наступающим новым годом!
      2. Anna Nifantova
        Anna Nifantova
        20.12.2021, 22:57
        Подскажите как сделать чтобы «день, час, минута, секунда» были английскими?
        1. Александр Мальцев
          Александр Мальцев
          24.12.2021, 13:30
          Необходимо просто указать их на английском (пример).
          1. Anna Nifantova
            Anna Nifantova
            24.12.2021, 13:59
            Спасибо большое. Главное тут было переписать правильно склонение числительных. Я бы не смогла.
        2. Aid
          Aid
          18.12.2021, 18:30
          Привет, а можно сделать так чтобы таймер был 30 минутный, что для этого надо сделать?
          1. Александр Мальцев
            Александр Мальцев
            19.12.2021, 03:35
            Привет!
            Нужно просто конечную дату установить на 30 минут больше, чем текущую, ну и убрать ненужный код, связанный с часами и днями (пример).
            1. Aid
              Aid
              19.12.2021, 21:08
              Спасибо)
          2. MI-5
            MI-5
            10.08.2021, 13:23
            Добрый день. Дни неправильно считаются. Ставлю на следующий день — показывает на месяц больше
            1. Александр Мальцев
              Александр Мальцев
              10.08.2021, 14:11
              Привет! В JavaScript месяц отсчитывается с нуля:
              // 5 января 2021
              new Date(2021, 0, 5);
              // 5 февраля 2021
              new Date(2021, 1, 5);
              // 5 марта 2021
              new Date(2021, 2, 5);
              
              1. MI-5
                MI-5
                10.08.2021, 14:16
                Спасибо, но логичнее где-то изменить в скрипте. Тогда наверное учёт високосных годов сломается.

                что-то типа такого:
                var deadline = new Date(2021, 08, 11);
                deadline.setMonth(deadline.getMonth() — 1);

                и ставить уже нормальный месяц.

                В любом случае спасибо большое.
                1. Александр Мальцев
                  Александр Мальцев
                  11.08.2021, 16:27
                  Можно сделать так:
                  // конечная дата
                  const deadline = (function(y, m, d) { return new Date(y, m-1, d); })(2021, 08, 12);
                  Т.е. использовать её вместо этой:
                  const deadline = new Date(2021, 07, 12);
            Войдите, пожалуйста, в аккаунт, чтобы оставить комментарий.