Как создать таймер обратного отсчета в JavaScript

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

Что такое таймер обратного отсчета

Таймер обратного отсчета — это виртуальные часы, работающие на целевой странице. И он ведет обратный отсчет от определенной даты, чтобы указать начало (или конец) события.

На веб-сайтах электронной коммерции вы можете использовать таймер обратного отсчета, чтобы отобразить начало (или конец) предложения. Цель таймера — побудить клиентов совершить такие действия, как покупка товаров или услуг.

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

Обратите внимание, что таймер обратного отсчета, который вы собираетесь создать, можно использовать повторно, поэтому вы можете использовать его на любой целевой странице. Кроме того, вы можете использовать для создания нескольких таймеров на одной странице.

Создание структуры проекта

Сначала создайте папку проекта с именем countdown-timer. Внутри этой папки создайте три подпапки: js, css и img, в которых будут храниться файлы JavaScript, CSS и изображения.

Во-вторых, создайте style.css в папке css, app.js и countdown.js в папке js и index.html в папке countdown-timer :

В-третьих, скачайте эту картинку фейерверка и скопируйте ее в папку img. Вы будете использовать это изображение в качестве фона страницы обратного отсчета до Нового года.

Структура проекта будет выглядеть так:

Структура проекта

Создание HTML-страницы

HTML-страница довольно проста, потому что вы будете генерировать большую часть HTML-кода из JavaScript.

Ниже показана полная HTML-страница:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript Countdown Timer - New Year Countdown</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <h1>New Year Countdown</h1>
    <div class="countdown-timer"></div>
    <div class="message"></div>
    <div class="year"></div>

    <script src="js/countdown.js"></script>
    <script src="js/app.js"></script>

</body>
</html>

В файле index.html вы размещаете ссылку на файл style.css в разделе <head> и файлы countdown.js и app.js в разделе <body>.

Обратите внимание, что файл countdown.js должен располагаться перед файлом app.js, потому что app.js будет использовать объекты из файла countdown.js.

Раздел <body> состоит из четырех элементов:

  • Заголовок 1( <h1> ). Этот элемент покажет заголовок. Это может быть все, что описывает обратный отсчет, например, обратный отсчет до Нового года.
  • <div> с countdown-timer класса. Этот элемент будет отображать обратный отсчет.
  • <div> с классом message. Этот элемент будет отображать сообщение, когда обратный отсчет завершится.
  • И <div> с классом year. Этот элемент покажет Новый год, например, 2021.

Краткий обзор объекта Date

Чтобы создать таймер, вам нужно будет работать с объектом Date, который доступен во всех веб-браузерах.

Объект Date представляет один момент времени. Он содержит число, представляющее миллисекунды с 1 января 1970 года по всемирному координированному времени.

Ниже показано, как создать новый объект Date, представляющий текущую дату и время:

const now = new Date();

В этом примере показано, как вызвать метод getTime() объекта Date, чтобы получить количество миллисекунд с January 1, 1970 00:00:00 UTC :

const time = now.getTime();
console.log(time);

Чтобы создать новый объект Date с указанной датой и временем, вы можете передать строку даты в конструктор Date() следующим образом:

const d = new Date('February 02, 2020 01:02:03');
console.log(d.getTime()); // 1580580123000

Чтобы вычислить количество миллисекунд между двумя временами, вы вызываете метод getTime() и используете оператор -. Например:

const d1 = new Date('September 17, 2020 00:00:00');
const d2 = new Date('September 19, 2020 01:00:00');

const time = d2.getTime() - d1.getTime();
console.log(time); // 176400000

Расчет оставшегося времени

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

Следующий код объявляет переменную времени со значением 150000 миллисекунд:

const time = 150000;
// ms

Чтобы преобразовать миллисекунды в минуты, вы делите миллисекунды на 1000, чтобы получить секунды, и делите секунды на 60, чтобы получить минуты. Например:

console.log(time / 1000 / 60);

Выход:

2.5

Чтобы получить оставшиеся минуты(2), вы используете функцию Math.floor() :

const minutes = Math.floor(time / 1000 / 60);
console.log(minutes); // 2

Чтобы получить оставшиеся секунды(30), вы используете оператор модуля( % ), который возвращает остаток от деления:

const seconds = Math.floor(time / 1000) % 60;
console.log(seconds); // 30

Разработка класса обратного отсчета

Сначала создайте новый класс CountDown в файле countdown.js :

class CountDown {
}

Класс CountDown должен быть инициализирован тремя аргументами:

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

Конструктор класса будет выглядеть так:

class CountDown {
    constructor(expiredDate, onRender, onComplete) {
        this.onRender = onRender;
        this.onComplete = onComplete;
        // handle the expired Date
        ..
    }
}

Основываясь на аргументе expiredDate, вы можете рассчитать оставшееся время в миллисекундах:

const currentTime = new Date().getTime();
const timeRemaining = expiredDate.getTime() - currentTime;

Поскольку вам потребуется доступ к оставшемуся времени( timeRemaining ) в методах класса, вы должны определить его как свойство класса CountDown.

Метод setExpiredDate()

Ниже определяется новый метод setExpiredDate(), который инициализирует свойство timeRemaining :

 setExpiredDate(expiredDate) {
    // get the current time
    const currentTime = new Date().getTime();
    // calculate the remaining time 
    this.timeRemaining = expiredDate.getTime() - currentTime;
}

Если timeRemaining больше нуля, метод setExpiredDate() выполнит метод start() для запуска таймера. В противном случае он выполнит метод complete().

setExpiredDate() будет выглядеть так:

setExpiredDate(expiredDate) {
    // get the current time
    const currentTime = new Date().getTime();

    // calculate the remaining time 
    this.timeRemaining = expiredDate.getTime() - currentTime;

    // should the countdown completes or start
    this.timeRemaining > 0 ?
        this.start() :
        this.complete();
}

Обратите внимание, что мы используем тернарный оператор ?: для выполнения метода complete() или start() на основе значения свойства this.timeRemaining.

Метод complete()

Метод complete() проверяет, передан ли обратный вызов onComplete, и вызывает его. Если onComplete недоступен, complete() ничего не сделает.

complete() {
    if(typeof this.onComplete === 'function') {
        onComplete();
    }
}

Функция start()

Метод start() уменьшает свойство timeRemaining каждую секунду(1000 мс).

Если оставшееся время меньше нуля, метод start() :

  • Сначала вызовите метод complete().
  • Во-вторых, очистите таймер с помощью функции clearInterval().
start() {
    //  setup a timer
    const intervalId = setInterval(() => {
        // update the timer  
        this.timeRemaining -= 1000;

        if(this.timeRemaining < 0) {
            // call the callback
            complete();

            // clear the interval if expired
            clearInterval(intervalId);
        }

    }, 1000);
}

Если оставшееся время больше нуля, метод start() должен вызывать метод, который выполняет обратный вызов onRender.

Метод getTime()

Следующий метод getTime() возвращает объект, содержащий оставшиеся дни, часы, минуты и секунды на основе свойства timeRemaining.

  getTime() {
    return {
        days: Math.floor(this.timeRemaining / 1000 / 60 / 60 / 24),
        hours: Math.floor(this.timeRemaining / 1000 / 60 / 60) % 24,
        minutes: Math.floor(this.timeRemaining / 1000 / 60) % 60,
        seconds: Math.floor(this.timeRemaining / 1000) % 60
    };
}

Метод update()

Далее определяется метод update(), который вызывает обратный вызов onRender() с текущим оставшимся объектом времени, возвращаемым методом getTime() :

update() {
    if(typeof this.onRender === 'function') {
        this.onRender(this.getTime());
    }
}

Метод start() будет вызывать метод update() в начале и каждую секунду после этого:

start() {
    // update the countdown
    this.update();

    //  setup a timer
    const intervalId = setInterval(() => {
        // update the timer  
        this.timeRemaining -= 1000;

        if (this.timeRemaining < 0) {
            // call the callback
            complete();

            // clear the interval if expired
            clearInterval(intervalId);
        } else {
            this.update();
        }

    }, 1000);
}

Ниже показан полный класс CountDown :

class CountDown {
    constructor(expiredDate, onRender, onComplete) {
        this.setExpiredDate(expiredDate);

        this.onRender = onRender;
        this.onComplete = onComplete;
    }

    setExpiredDate(expiredDate) {
        // get the current time
        const currentTime = new Date().getTime();

        // calculate the remaining time 
        this.timeRemaining = expiredDate.getTime() - currentTime;

        this.timeRemaining <= 0 ?
            this.complete() :
            this.start();
    }


    complete() {
        if (typeof this.onComplete === 'function') {
            onComplete();
        }
    }
    getTime() {
        return {
            days: Math.floor(this.timeRemaining / 1000 / 60 / 60 / 24),
            hours: Math.floor(this.timeRemaining / 1000 / 60 / 60) % 24,
            minutes: Math.floor(this.timeRemaining / 1000 / 60) % 60,
            seconds: Math.floor(this.timeRemaining / 1000) % 60
        };
    }

    update() {
        if (typeof this.onRender === 'function') {
            this.onRender(this.getTime());
        }
    }

    start() {
        // update the countdown
        this.update();

        //  setup a timer
        const intervalId = setInterval(() => {
            // update the timer  
            this.timeRemaining -= 1000;

            if (this.timeRemaining < 0) {
                // call the callback
                complete();

                // clear the interval if expired
                clearInterval(intervalId);
            } else {
                this.update();
            }

        }, 1000);
    }
}

Обратный отсчет до Нового года

Во-первых, создайте новую функцию с именем getNewYear(), которая возвращает новый год:

const getNewYear =() => {
    const currentYear = new Date().getFullYear();
    return new Date(`January 01 ${currentYear + 1} 00:00:00`);
};

Во-вторых, выберите и обновите элемент .year. Он покажет четырехзначный номер нового года, например, 2021:

// update the year element
const year = document.querySelector('.year');
year.innerHTML = getNewYear().getFullYear();

В-третьих, выберите .countdown-timer, .message и h1 :

// select elements
const app = document.querySelector('.countdown-timer');
const message = document.querySelector('.message');
const heading = document.querySelector('h1');

В-четвертых, определите функцию формата, которая дополняет число, если оно меньше 10. Например, 5 будет равно 05. Но 10 останется прежним.

const format =(t) => {
    return t < 10 ? '0' + t : t;
};

В-пятых, определите метод render(), который составляет HTML-разметку из объекта времени и обновляет ее до элемента .countdown-timer. Он покажет оставшиеся дни, часы, минуты и секунды.

const render =(time) => {
    app.innerHTML = `
        <div class="count-down">
            <div class="timer">
                <h2 class="days">${format(time.days)}</h2>
                <small>Days</small>
            </div>
            <div class="timer">
                <h2 class="hours">${format(time.hours)}</h2>
                <small>Hours</small>
            </div>
            <div class="timer">
                <h2 class="minutes">${format(time.minutes)}</h2>
                <small>Minutes</small>
            </div>
            <div class="timer">
                <h2 class="seconds">${format(time.seconds)}</h2>
                <small>Seconds</small>
            </div>
        </div>
        `;
};

Когда обратный отсчет завершается, отображается сообщение, например, "Happy New Year".

Следующая showMessage() отображает сообщение « Happy New Year. Кроме того, он очищает содержимое элемента .countdown-timer и скрывает элемент заголовка:

const showMessage =() => {
    message.innerHTML = `Happy New Year ${newYear}!`;
    app.innerHTML = '';
    heading.style.display = 'none';
};

В-шестых, обратный отсчет до Нового года должен отображать приветственное сообщение с Новым годом в течение определенного периода времени, а затем снова отображать обратный отсчет до Нового года.

Следующий код определяет функцию, которая скрывает приветственное сообщение и показывает элемент заголовка:

const hideMessage =() => {
    message.innerHTML = '';
    heading.style.display = 'block';
}

В-седьмых, определите функцию complete(), которая показывает сообщение в течение определенного периода времени, а затем скрывает его. Кроме того, она устанавливает expiredDate на Новый год:

const complete =() => {
    showMessage();
    // restart the countdown after showing the 
    // greeting message for a day()
    setTimeout(() => {
        hideMessage();
        countdownTimer.setExpiredDate(getNewYear());
    }, 1000 * 60 * 24);
};

Наконец, создайте новый экземпляр CountDown и передайте дату Нового года, функцию render и функцию complete в его конструктор:

const countdownTimer = new CountDown(
    getNewYear(),
    render,
    complete
);

Ниже показан полный файл app.js :

// Get the new year 
const getNewYear = () => {
    const currentYear = new Date().getFullYear();
    return new Date(`January 01 ${currentYear + 1} 00:00:00`);
};

// update the year element
const year = document.querySelector('.year');
year.innerHTML = getNewYear().getFullYear();

// select elements
const app = document.querySelector('.countdown-timer');
const message = document.querySelector('.message');
const heading = document.querySelector('h1');


const format = (t) => {
    return t < 10 ? '0' + t : t;
};

const render = (time) => {
    app.innerHTML = `
        <div class="count-down">
            <div class="timer">
                <h2 class="days">${format(time.days)}</h2>
                <small>Days</small>
            </div>
            <div class="timer">
                <h2 class="hours">${format(time.hours)}</h2>
                <small>Hours</small>
            </div>
            <div class="timer">
                <h2 class="minutes">${format(time.minutes)}</h2>
                <small>Minutes</small>
            </div>
            <div class="timer">
                <h2 class="seconds">${format(time.seconds)}</h2>
                <small>Seconds</small>
            </div>
        </div>
        `;
};


const showMessage = () => {
    message.innerHTML = `Happy New Year ${newYear}!`;
    app.innerHTML = '';
    heading.style.display = 'none';
};

const hideMessage = () => {
    message.innerHTML = '';
    heading.style.display = 'block';
};

const complete = () => {
    showMessage();

    // restart the countdown after showing the 
    // greeting message for a day ()
    setTimeout(() => {
        hideMessage();
        countdownTimer.setExpiredDate(getNewYear());
    }, 1000 * 60 * 60 * 24);
};

const countdownTimer = new CountDown(
    getNewYear(),
    render,
    complete
);

Если вы откроете index.html, вы увидите, что обратный отсчет до Нового года уже запущен.

Заключение

В этом уроке вы узнали, как:

  • Использовать класс ES6, чтобы определить повторно используемый компонент таймера обратного отсчета.
  • Пользоваться объектом Date для управления временем.
  • Использовать setInterval() и clearInterval() для создания и отмены повторяющегося действия по времени.
Рейтинг
( Пока оценок нет )
Александр Русаков / автор статьи
Программист, разработчик, 12 лет опыта работы в крупных компаниях. Быстро освоил typescript, делюсь своими знаниями на страницах этого сайта.
Загрузка ...
JavaScript и TypeScript