JavaScript 倒计时

摘要:在本教程中,您将学习如何开发可复用的 JavaScript 倒计时器。

什么是倒计时器

倒计时器是运行在登录页面上的虚拟时钟。它从某个日期开始倒计时,以指示事件的开始(或结束)。

在电子商务网站上,您可以使用倒计时器来显示优惠的开始(或结束)。倒计时的目的是敦促客户采取行动,例如购买产品或服务。

在本教程中,您将学习如何从头开始在 JavaScript 中创建倒计时器。您还将学习如何使用它来构建新年倒计时器。

以下是最终的新年倒计时登录页面:https://javascripttutorial.net/sample/dom/countdown-timer/

请注意,您将要构建的倒计时器是可复用的,因此您可以在任何登录页面上使用它。此外,您还可以使用此倒计时在单个页面上创建多个倒计时器。

创建项目结构

首先,创建一个名为 countdown-timer 的项目文件夹。在这个文件夹中,创建三个子文件夹:jscssimg,分别用来存储 JavaScript、CSS 和图像文件。

其次,在 css 文件夹中创建 style.css,在 js 文件夹中创建 app.jscountdown.js 文件,并在 countdown-timer 文件夹中创建 index.html

第三,下载此烟花图片 并将其复制到 img 文件夹中。您将使用此图片作为新年倒计时页面的背景。

项目结构如下所示

创建 HTML 页面

HTML 页面非常简单,因为您将从 JavaScript 生成大部分 HTML 代码。

以下是完整的 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>Code language: HTML, XML (xml)

index.html 文件中,您将 style.css 文件的链接放在 <head> 部分,将 countdown.jsapp.js 文件放在 <body> 部分。

请注意,countdown.js 文件必须出现在 app.js 文件之前,因为 app.js 将使用 countdown.js 文件中的对象。

<body> 部分有四个元素

  • 一个标题 1 (<h1>)。此元素将显示标题。它可以是描述倒计时的任何内容,例如:新年倒计时。
  • 一个具有 countdown-timer 类的 <div>。此元素将显示倒计时。
  • 一个具有 message 类的 <div>。此元素将在倒计时完成时显示消息。
  • 以及一个具有 year 类的 <div>。此元素将显示新年,例如:2021。

Date 对象的快速概述

要创建计时器,您需要使用 Date 对象,该对象在所有 Web 浏览器中都可用。

Date 对象表示时间中的一个特定时刻。它包含一个数字,表示自 1970 年 1 月 1 日 UTC 以来经过的毫秒数。

以下是如何创建一个表示当前日期和时间的新 Date 对象

const now = new Date();Code language: JavaScript (javascript)

此示例显示了如何调用 Date 对象的 getTime() 方法来获取自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的毫秒数

const time = now.getTime();
console.log(time);Code language: JavaScript (javascript)

要使用指定的日期和时间创建一个新的 Date 对象,您可以将日期字符串传递到 Date() 构造函数中,如下所示

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

要计算两次时间之间的毫秒数,您可以调用 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); // 176400000Code language: JavaScript (javascript)

计算剩余时间

倒计时器需要计算自某个毫秒数以来的剩余天数、小时、分钟和秒数,并将此信息显示在网页上。

以下声明了一个名为 time 的变量,其值为 150000 毫秒

const time = 150000; // msCode language: JavaScript (javascript)

要将毫秒转换为分钟,您可以将毫秒除以 1000 以获得秒数,然后将秒数除以 60 以获得分钟数。例如

console.log(time / 1000 / 60); Code language: JavaScript (javascript)

输出

2.5Code language: CSS (css)

要获取剩余分钟数 (2),您可以使用 Math.floor() 函数

const minutes = Math.floor(time / 1000 / 60);
console.log(minutes); // 2Code language: JavaScript (javascript)

要获取剩余秒数 (30),您可以使用模运算符 ( % ),它返回除法的余数

const seconds = Math.floor(time / 1000) % 60;
console.log(seconds); // 30Code language: JavaScript (javascript)

开发 CountDown 类

首先,在 countdown.js 文件中创建一个新的 CountDown

class CountDown {
}Code language: JavaScript (javascript)

CountDown 类应使用三个参数进行初始化

  • 一个过期日期。
  • 一个负责呈现倒计时器的回调函数。
  • 以及另一个在倒计时完成时将被调用的回调函数。

CountDown 类的构造函数将如下所示

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

根据 expiredDate 参数,您可以计算剩余时间(以毫秒为单位)

const currentTime = new Date().getTime();
const timeRemaining = expiredDate.getTime() - currentTime;Code language: JavaScript (javascript)

由于您需要在类的所有方法中访问剩余时间 (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;
}Code language: JavaScript (javascript)

如果 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();
}Code language: JavaScript (javascript)

请注意,我们使用了 三元运算符 ?: 根据 this.timeRemaining 属性的值来执行 complete()start() 方法。

complete() 方法

complete() 方法检查 onComplete 回调是否已传递,并调用它。如果 onComplete 不可用,complete() 不会执行任何操作。

complete() {
    if (typeof this.onComplete === 'function') {
        onComplete();
    }
}Code language: JavaScript (javascript)

start() 方法

start() 方法每秒 (1000 毫秒) 减少 timeRemaining 属性一次。

如果剩余时间小于零,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);
}Code language: JavaScript (javascript)

如果剩余时间大于零,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
    };
}Code language: JavaScript (javascript)

update() 方法

以下定义了 update() 方法,该方法使用 getTime() 方法返回的当前剩余时间对象来调用 onRender() 回调函数

update() {
    if (typeof this.onRender === 'function') {
        this.onRender(this.getTime());
    }
}Code language: JavaScript (javascript)

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);
}Code language: JavaScript (javascript)

以下是完整的 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);
    }
}Code language: JavaScript (javascript)

构建新年倒计时

首先,创建一个名为 getNewYear() 的新函数,该函数返回新年

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

其次,选择并更新 .year 元素。它将显示新年的四位数年份数字,例如:2021

// update the year element
const year = document.querySelector('.year');
year.innerHTML = getNewYear().getFullYear();Code language: JavaScript (javascript)

第三,选择 .countdown-timer.messageh1 元素

// select elements
const app = document.querySelector('.countdown-timer');
const message = document.querySelector('.message');
const heading = document.querySelector('h1');Code language: JavaScript (javascript)

第四,定义一个格式化函数,如果数字小于 10,则用 '0' 填充数字。例如,5 将变为 05。但 10 将保持不变。

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

第五,定义一个 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>
        `;
};
Code language: HTML, XML (xml)

第五,倒计时完成后,它将显示一条消息,例如:"新年快乐"

以下 showMessage() 函数显示 新年快乐 消息。此外,它还清除 .countdown-timer 元素的内容并隐藏标题元素

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

第六,新年倒计时应在一段时间内显示新年快乐的祝贺消息,然后再次显示新年倒计时。

以下定义了一个函数,用于隐藏祝贺消息并显示标题元素

const hideMessage = () => {
    message.innerHTML = '';
    heading.style.display = 'block';
}Code language: JavaScript (javascript)

第七,定义一个 complete() 函数,该函数在一段时间内显示消息,然后将其隐藏。此外,它还将 expiredDate 设置为新年

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

最后,创建新的 CountDown 实例,并将新年日期、render 函数和 complete 函数传递到其构造函数中

const countdownTimer = new CountDown(
    getNewYear(),
    render,
    complete
);Code language: JavaScript (javascript)

以下是完整的 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
);Code language: JavaScript (javascript)

如果您打开 index.html,您会看到新年倒计时已经启动并运行:https://tutorial.javascript.ac.cn/sample/dom/countdown-timer/

总结

在本教程中,您学习了如何

  • 使用 ES6 类 来定义可复用的倒计时器组件。
  • 使用 Date 对象来操作时间。
  • 使用 setInterval()clearInterval() 来创建和取消定时重复操作。
本教程对您有帮助吗?