僅用18行JavaScript實現(xiàn)一個倒數(shù)計時器
前言
有時,您將需要構(gòu)建一個JavaScript倒數(shù)時鐘。您可能有活動,銷售,促銷或游戲。您可以使用原始JavaScript構(gòu)建時鐘,而不用尋找最近的插件。雖然有很多很棒的時鐘插件,但是使用原始JavaScript可以帶來以下好處:
- 您的代碼將是輕量級的,因為它將具有零依賴性。
- 您的網(wǎng)站將表現(xiàn)更好。您無需加載外部腳本和樣式表。
- 您將擁有更多控制權(quán)。您將構(gòu)建時鐘,使其行為完全符合您希望的方式(而不是嘗試將插件彎曲到您的意愿)。
因此,事不宜遲,這里介紹了如何僅用18行JavaScript來制作自己的倒計時時鐘

基本時鐘:倒數(shù)到特定的日期或時間
以下是創(chuàng)建基本時鐘所涉及步驟的快速概述:
- 設(shè)置有效的結(jié)束日期。
- 計算剩余時間。
- 將時間轉(zhuǎn)換為可用格式。
- 將時鐘數(shù)據(jù)輸出為可重復(fù)使用的對象。
- 在頁面上顯示時鐘,并在時鐘為零時停止時鐘。
設(shè)定有效的結(jié)束日期
首先,您需要設(shè)置一個有效的結(jié)束日期。這應(yīng)該是JavaScript的Date.parse()方法可以理解的任何格式的字符串。例如:
在ISO 8601格式:
- const deadline = '2015-12-31';
簡短格式:
- const deadline = '31/12/2015';
或者,長格式:
- const deadline = 'December 31 2015';
這些格式中的每一種都允許您指定確切的時間和時區(qū)(對于ISO日期,則為UTC的偏移量)。例如:
- const deadline = 'December 31 2015 23:59:59 GMT+0200';
您可以在本文中閱讀有關(guān)JavaScript中日期格式的更多信息。
計算剩余時間
下一步是計算剩余時間。我們需要編寫一個函數(shù),該函數(shù)需要一個表示給定結(jié)束時間的字符串(如上所述)。然后,我們計算該時間與當前時間之間的時差??雌饋硐襁@樣:
- function getTimeRemaining(endtime){
- const total = Date.parse(endtime) - Date.parse(new Date());
- const seconds = Math.floor( (total/1000) % 60 );
- const minutes = Math.floor( (total/1000/60) % 60 );
- const hours = Math.floor( (total/(1000*60*60)) % 24 );
- const days = Math.floor( total/(1000*60*60*24) );
- return {
- total,
- days,
- hours,
- minutes,
- seconds
- };
- }
首先,我們創(chuàng)建一個變量total,以保留剩余時間直到截止日期。該Date.parse()函數(shù)將時間字符串轉(zhuǎn)換為毫秒值。這使我們可以相減兩次,并獲得兩者之間的時間量。
- const total = Date.parse(endtime) - Date.parse(new Date());
將時間轉(zhuǎn)換為可用格式
現(xiàn)在,我們要將毫秒轉(zhuǎn)換為天,小時,分鐘和秒。讓我們以秒為例:
- const seconds = Math.floor( (t/1000) % 60 );
讓我們分解一下這里發(fā)生的事情。
- 將毫秒除以1000可轉(zhuǎn)換為秒: (t/1000)
- 將總秒數(shù)除以60,然后取余數(shù)。您不希望所有的秒數(shù),僅需要計算分鐘數(shù)之后剩下的秒數(shù):(t/1000) % 60
- 四舍五入到最接近的整數(shù)。這是因為您需要完整的秒數(shù),而不是幾分之一秒:Math.floor( (t/1000) % 60 )
重復(fù)此邏輯,將毫秒轉(zhuǎn)換為分鐘,小時和天。
輸出時鐘數(shù)據(jù)作為可重用對象
準備好幾天,幾小時,幾分鐘和幾秒鐘之后,我們現(xiàn)在可以將數(shù)據(jù)作為可重用的對象返回:
- return {
- total,
- days,
- hours,
- minutes,
- seconds
- };
該對象允許您調(diào)用函數(shù)并獲取任何計算值。這是如何獲取剩余時間的示例:
- getTimeRemaining(deadline).minutes
方便吧?
顯示時鐘并在達到零時停止
現(xiàn)在,我們有了一個可以花費剩余的天,小時,分鐘和秒的功能,我們可以構(gòu)建時鐘了。首先,我們將創(chuàng)建以下HTML元素來保存時鐘:
然后,我們將編寫一個在新div中輸出時鐘數(shù)據(jù)的函數(shù):
- function initializeClock(id, endtime) {
- const clock = document.getElementById(id);
- const timeinterval = setInterval(() => {
- const t = getTimeRemaining(endtime);
- clock.innerHTML = 'days: ' + t.days + '<br>' +
- 'hours: '+ t.hours + '<br>' +
- 'minutes: ' + t.minutes + '<br>' +
- 'seconds: ' + t.seconds;
- if (t.total <= 0) {
- clearInterval(timeinterval);
- }
- },1000);
- }
該函數(shù)有兩個參數(shù)。這些是包含我們時鐘的元素的ID,以及倒計時的結(jié)束時間。在函數(shù)內(nèi)部,我們將聲明一個clock變量并將其用于存儲對我們的時鐘容器div的引用。這意味著我們不必繼續(xù)查詢DOM。
接下來,我們將使用setInterval每秒執(zhí)行一個匿名函數(shù)。此功能將執(zhí)行以下操作:
- 計算剩余時間。
- 將剩余時間輸出到我們的div。
- 如果剩余時間為零,請停止計時。
- 此時,剩下的唯一步驟是像這樣運行時鐘:
- initializeClock('clockdiv', deadline);
恭喜你!現(xiàn)在,您僅用18行JavaScript就擁有了一個基本時鐘。
準備顯示時鐘
在設(shè)置時鐘樣式之前,我們需要進行一些細化。
- 消除初始延遲,使您的時鐘立即顯示。
- 提高時鐘腳本的效率,以免持續(xù)重建整個時鐘。
- 根據(jù)需要添加前導(dǎo)零。
消除初始延遲
在時鐘中,我們習慣于setInterval每秒更新一次顯示。多數(shù)情況下,這很好,除非在開始時會有一秒鐘的延遲。要消除此延遲,我們必須在間隔開始之前更新一次時鐘。
讓我們將要傳遞給setInterval它的匿名函數(shù)移到其自己的獨立函數(shù)中。我們可以命名這個函數(shù)updateClock。在updateClock外部調(diào)用該函數(shù)setInterval,然后在內(nèi)部再次調(diào)用setInterval。這樣,時鐘顯示就沒有延遲了。
在您的JavaScript中,替換為:
- const timeinterval = setInterval(() => { ... },1000);
有了這個:
- function updateClock(){
- const t = getTimeRemaining(endtime);
- clock.innerHTML = 'days: ' + t.days + '<br>' +
- 'hours: '+ t.hours + '<br>' +
- 'minutes: ' + t.minutes + '<br>' +
- 'seconds: ' + t.seconds;
- if (t.total <= 0) {
- clearInterval(timeinterval);
- }
- }
- updateClock(); // run function once at first to avoid delay
- var timeinterval = setInterval(updateClock,1000);
避免持續(xù)重建時鐘
我們需要使時鐘腳本更高效。我們只想更新時鐘中的數(shù)字,而不是每秒重新構(gòu)建整個時鐘。實現(xiàn)此目的的一種方法是將每個數(shù)字放在span標簽中,然后僅更新這些跨度的內(nèi)容。
這是HTML:
- <div id="clockdiv">
- Days: <span class="days"></span><br>
- Hours: <span class="hours"></span><br>
- Minutes: <span class="minutes"></span><br>
- Seconds: <span class="seconds"></span>
- </div>
現(xiàn)在讓我們參考這些元素。在clock定義變量的位置之后添加以下代碼
- const daysSpan = clock.querySelector('.days');
- const hoursSpan = clock.querySelector('.hours');
- const minutesSpan = clock.querySelector('.minutes');
- const secondsSpan = clock.querySelector('.seconds');
接下來,我們需要更改updateClock功能以及更新數(shù)字。新代碼如下所示:
- function updateClock(){
- const t = getTimeRemaining(endtime);
- daysSpan.innerHTML = t.days;
- hoursSpan.innerHTML = t.hours;
- minutesSpan.innerHTML = t.minutes;
- secondsSpan.innerHTML = t.seconds;
- ...
- }
添加前導(dǎo)零
現(xiàn)在時鐘不再每秒都在重建,我們還有另一件事要做:添加前導(dǎo)零。例如,不是讓時鐘顯示7秒,而是顯示07秒。一種簡單的方法是在數(shù)字的開頭添加字符串“ 0”,然后切掉最后兩位數(shù)字。
例如,要在“ seconds”值上添加前導(dǎo)零,您可以對此進行更改:
- secondsSpan.innerHTML = t.seconds;
對此:
- secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);
如果需要,您也可以在分鐘和小時中添加前導(dǎo)零。如果您走了這么遠,恭喜!您的時鐘現(xiàn)在可以顯示了。
注意:您可能需要在CodePen中單擊“重新運行”才能開始倒計時。
更進一步
下面的示例演示如何針對某些用例擴展時鐘。它們都是基于上面看到的基本示例。
自動安排時鐘
假設(shè)我們希望時鐘顯示在某些日子,而不是其他日子。例如,我們可能會發(fā)生一系列事件,并且不想每次都手動更新時鐘。這是提前安排事情的方法。
通過在CSS中將其display屬性設(shè)置為隱藏時鐘none。然后將以下內(nèi)容添加到initializeClock函數(shù)中(以開頭的行之后var clock)。一旦initializeClock調(diào)用此函數(shù),這將導(dǎo)致時鐘僅顯示:
- clock.style.display = 'block';
接下來,我們可以指定顯示時鐘的日期。這將替換deadline變量:
- const schedule = [
- ['Jul 25 2015', 'Sept 20 2015'],
- ['Sept 21 2015', 'Jul 25 2016'],
- ['Jul 25 2016', 'Jul 25 2030']
- ];
schedule數(shù)組中的每個元素代表一個開始日期和一個結(jié)束日期。如上所述,可以包括時間和時區(qū),但是我在這里使用了簡單的日期來保持代碼的可讀性。
最后,當用戶加載頁面時,我們需要檢查是否在指定的時間范圍內(nèi)。該代碼應(yīng)替換先前對該initializeClock函數(shù)的調(diào)用。
- // iterate over each element in the schedule
- for (var i=0; i<schedule.length; i++) {
- var startDate = schedule[i][0];
- var endDate = schedule[i][1];
- // put dates in milliseconds for easy comparisons
- var startMs = Date.parse(startDate);
- var endMs = Date.parse(endDate);
- var currentMs = Date.parse(new Date());
- // if current date is between start and end dates, display clock
- if (endMs > currentMs && currentMs >= startMs ) {
- initializeClock('clockdiv', endDate);
- }
- }
- schedule.forEach(([startDate, endDate]) => {
- // put dates in milliseconds for easy comparisons
- const startMs = Date.parse(startDate);
- const endMs = Date.parse(endDate);
- const currentMs = Date.parse(new Date());
- // if current date is between start and end dates, display clock
- if (endMs > currentMs && currentMs >= startMs ) {
- initializeClock('clockdiv', endDate);
- }
- });
現(xiàn)在,您可以提前安排時鐘,而無需手動更新。您可以根據(jù)需要縮短代碼。為了便于閱讀,我讓我變得冗長。
從用戶到達起將計時器設(shè)置為10分鐘
用戶到達或開始特定任務(wù)后,有必要在給定的時間內(nèi)設(shè)置倒計時。我們將在此處將計時器設(shè)置為10分鐘,但是您可以使用任意時間。
我們需要做的就是deadline用這個替換變量:
- const timeInMinutes = 10;
- const currentTime = Date.parse(new Date());
- const deadline = new Date(currentTime + timeInMinutes*60*1000);
該代碼將花費當前時間,并增加十分鐘。這些值將轉(zhuǎn)換為毫秒,因此可以將它們加在一起并變成新的截止日期。
現(xiàn)在,我們有了一個時鐘,可以從用戶到達時開始倒數(shù)十分鐘。隨意玩耍,嘗試不同的時間長度。
跨頁面保持時鐘進度
有時,有必要將時鐘狀態(tài)保留的時間不僅限于當前頁面。如果我們想在整個網(wǎng)站上設(shè)置10分鐘的計時器,則我們不希望在用戶轉(zhuǎn)到其他頁面時將其重置。
一種解決方案是將時鐘的結(jié)束時間保存在cookie中。這樣,導(dǎo)航到新頁面不會將結(jié)束時間重置為現(xiàn)在的十分鐘。
這是邏輯:
如果Cookie中記錄了截止日期,請使用該截止日期。
如果不存在該cookie,則設(shè)置一個新的截止日期并將其存儲在cookie中。
要實現(xiàn)這一點,請用deadline以下內(nèi)容替換變量:
- let deadline;
- // if there's a cookie with the name myClock, use that value as the deadline
- if(document.cookie && document.cookie.match('myClock')){
- // get deadline value from cookie
- deadline = document.cookie.match(/(^|;)myClock=([^;]+)/)[2];
- } else {
- // otherwise, set a deadline 10 minutes from now and
- // save it in a cookie with that name
- // create deadline 10 minutes from now
- const timeInMinutes = 10;
- const currentTime = Date.parse(new Date());
- deadline = new Date(currentTime + timeInMinutes*60*1000);
- // store deadline in cookie for future reference
- document.cookie = 'myClock=' + deadline + '; path=/; domain=.yourdomain.com';
- }
這段代碼利用了cookie和正則表達式,它們本身就是單獨的主題。因此,我在這里不再贅述。需要注意的一件事是,您需要更改.yourdomain.com為實際域。
有關(guān)客戶端事件的重要警告
JavaScript日期和時間是從用戶計算機中獲取的。這意味著用戶可以通過更改計算機上的時間來影響JavaScript時鐘。在大多數(shù)情況下,這無關(guān)緊要。但是,在某些超級敏感的情況下,有必要從服務(wù)器獲取時間??梢允褂靡恍㏄HP或Ajax來完成,這兩者都超出了本教程的范圍。
從服務(wù)器獲取時間后,我們可以使用本教程中的相同技術(shù)來使用它。
加起來
閱讀完本文中的示例之后,您現(xiàn)在知道如何僅用幾行原始JavaScript代碼創(chuàng)建自己的倒數(shù)計時器!我們已經(jīng)研究了如何制作基本的倒數(shù)時鐘并有效顯示它。我們還介紹了添加一些有用的附加功能,包括計劃,絕對時間和相對時間,以及使用Cookie保留頁面和站點訪問之間的狀態(tài)。
完整代碼
- <!DOCTYPE html>
- <html lang="zh">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <meta http-equiv="X-UA-Compatible" content="ie=edge" />
- <title>Countdown Clock</title>
- <style type="text/css">
- body{
- text-align: center;
- background: #00ECB9;
- font-family: sans-serif;
- font-weight: 100;
- }
- h1{
- color: #396;
- font-weight: 100;
- font-size: 40px;
- margin: 40px 0px 20px;
- }
- #clockdiv{
- font-family: sans-serif;
- color: #fff;
- display: inline-block;
- font-weight: 100;
- text-align: center;
- font-size: 30px;
- }
- #clockdiv > div{
- padding: 10px;
- border-radius: 3px;
- background: #00BF96;
- display: inline-block;
- }
- #clockdiv div > span{
- padding: 15px;
- border-radius: 3px;
- background: #00816A;
- display: inline-block;
- }
- .smalltext{
- padding-top: 5px;
- font-size: 16px;
- }
- </style>
- </head>
- <body>
- <h1>Countdown Clock</h1>
- <div id="clockdiv">
- <div>
- <span class="days"></span>
- <div class="smalltext">Days</div>
- </div>
- <div>
- <span class="hours"></span>
- <div class="smalltext">Hours</div>
- </div>
- <div>
- <span class="minutes"></span>
- <div class="smalltext">Minutes</div>
- </div>
- <div>
- <span class="seconds"></span>
- <div class="smalltext">Seconds</div>
- </div>
- </div>
- <script type="text/javascript">
- function getTimeRemaining(endtime) {
- const total = Date.parse(endtime) - Date.parse(new Date());
- const seconds = Math.floor((total / 1000) % 60);
- const minutes = Math.floor((total / 1000 / 60) % 60);
- const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
- const days = Math.floor(total / (1000 * 60 * 60 * 24));
- return {
- total,
- days,
- hours,
- minutes,
- seconds
- };
- }
- function initializeClock(id, endtime) {
- const clock = document.getElementById(id);
- const daysSpan = clock.querySelector('.days');
- const hoursSpan = clock.querySelector('.hours');
- const minutesSpan = clock.querySelector('.minutes');
- const secondsSpan = clock.querySelector('.seconds');
- function updateClock() {
- const t = getTimeRemaining(endtime);
- daysSpan.innerHTML = t.days;
- hoursSpan.innerHTML = ('0' + t.hours).slice(-2);
- minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);
- secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);
- if (t.total <= 0) {
- clearInterval(timeinterval);
- }
- }
- updateClock();
- const timeinterval = setInterval(updateClock, 1000);
- }
- const deadline = new Date(Date.parse(new Date()) + 15 * 24 * 60 * 60 * 1000);
- initializeClock('clockdiv', deadline);
- </script>
- </body>
- </html>