天天看點

18行JavaScript代碼建構一個倒數計時器

18行JavaScript代碼建構一個倒數計時器

英文 | https://www.sitepoint.com    作者 | Nilson Jacques

有時候,你會需要建構一個JavaScript倒計時時鐘。你可能會有一個活動、一個銷售、一個促銷或一個遊戲。你可以用原生的JavaScript建構一個時鐘,而不是去找一個插件。盡管有很多很棒的時鐘插件,但是使用原生JavaScript可以帶來以下好處:

  • 你的代碼将是輕量級的,因為它将具有零依賴性。
  • 你的網站将表現得更好。你不需要加載外部腳本和樣式表。
  • 你将擁有更多的控制權。你将會建立一個完全按照你的意願來表現的時鐘。

是以,廢話不多說,下面是如何在短短的18行JavaScript中制作自己的倒計時鐘。

1、基本時鐘:倒數到特定的日期或時間

以下是建立基本時鐘所需步驟的簡要概述:

  • 設定有效的結束日期。
  • 計算剩餘時間。
  • 将時間轉換為可用格式。
  • 将時鐘資料輸出為可重複使用的對象。
  • 在頁面上顯示時鐘,并在時鐘為零時停止時鐘。

2、設定有效的結束日期

首先,你需要設定一個有效的結束日期。這應該是JavaScript的 Date.parse() 方法可以了解的任何格式的字元串。例如:

ISO 8601格式:

const deadline = '2015-12-31';      

簡短格式:

const deadline = '31/12/2015';      

或者,長格式:

const deadline = 'December 31 2015';      

這些格式中的每一種都允許你指定一個準确的時間和一個時區(或者在ISO日期的情況下指定一個與UTC的偏移)。例如:

const deadline = 'December 31 2015 23:59:59 GMT+0200';      

3、計算剩餘時間

下一步是計算剩餘時間。我們需要編寫一個函數,該函數需要一個表示給定結束時間的字元串(如上所述)。然後,我們計算該時間與目前時間之間的時差。看起來像這樣:

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
  };
}      

首先,我們要建立一個變量 total 以保留到截止日期為止的剩餘時間。Date.parse() 函數将時間字元串轉換為毫秒值,這樣我們就可以将兩次相減,得到中間的時間量。

const total = Date.parse(endtime) - Date.parse(new Date());      

4、将時間轉換為可用格式

現在我們要将毫秒轉換為天,小時,分鐘和秒。讓我們以秒為例:

const seconds = Math.floor( (t/1000) % 60 );      

讓我們分解一下這裡發生的事情。

  1. 将毫秒除以1000可轉換為秒:(t/1000)
  2. 将總秒數除以60,然後取餘數。你不需要所有的秒,隻需要計算分鐘數後剩下的那些:(t/1000) % 60
  3. 四舍五入到最接近的整數。這是因為你需要完整的秒數,而不是幾分之一秒:Math.floor((t/1000)%60)

重複此邏輯,将毫秒轉換為分鐘,小時和天。

5、将時鐘資料輸出為可重複使用的對象

在準備好幾天,幾小時,幾分鐘和幾秒鐘之後,我們現在可以将資料作為可重複使用的對象傳回:

return {
  total,
  days,
  hours,
  minutes,
  seconds
};      

這個對象允許你調用你的函數,并獲得任何計算值。這是如何擷取剩餘分鐘數的示例:

getTimeRemaining(deadline).minutes      

友善吧?

6、在頁面上顯示時鐘,并在時鐘為零時停止時鐘

現在我們有了一個可以吐出剩餘天數、小時、分鐘和秒數的函數,我們就可以建立我們的時鐘了。首先,我們将建立以下HTML元素來儲存時鐘:

<div id="clockdiv"></div>      

然後,我們将編寫一個函數,在新的div中輸出時鐘資料:

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);
}      

該函數有兩個參數,這兩個參數是包含時鐘的元素的id,以及倒計時的結束時間。在函數内部,我們将聲明一個 clock 變量,并使用它來儲存對時鐘容器div的引用。這意味着我們不必一直查詢DOM。

接下來,我們将使用 setInterval 每秒執行一個匿名函數。此功能将執行以下操作:

  • 計算剩餘時間。
  • 将剩餘時間輸出到我們的div。
  • 如果剩餘時間為零停止計時。

此時,剩下的唯一步驟是像這樣運作時鐘:

initializeClock('clockdiv', deadline);      

恭喜你!現在,你僅用18行JavaScript就擁有了一個基本時鐘。

7、準備展示你的時鐘

在設定時鐘樣式之前,我們需要進行一些改進。

  • 消除初始延遲,使你的時鐘立即顯示。
  • 讓時鐘腳本更有效率,這樣它就不會連續重建整個時鐘。
  • 根據需要添加前導零。

7.1 消除初始延遲

在時鐘中,我們使用 setInterval 每秒更新一次顯示。多數情況下,這很好,除非在開始時會有一秒鐘的延遲。要消除此延遲,我們必須在間隔開始之前更新一次時鐘。

讓我們将傳遞給 setInterval 的匿名函數移到其自己的單獨函數中,我們可以将此函數命名為 updateClock。在 setInterval 外調用一次 updateClock 函數,然後在 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(); // 首先運作一函數能以避免延遲
var timeinterval = setInterval(updateClock,1000);      

7.2 避免不斷重建時鐘

我們需要使時鐘腳本更高效,我們隻想更新時鐘中的數字,而不是每秒重建整個時鐘。實作此目的的一種方法是将每個數字放在 span 标簽内,并僅更新這些 span 的内容。

這是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>      

現在讓我們參考這些元素。在定義 clock 變量的位置之後添加以下代碼

const daysSpan = clock.querySelector('.days');
const hoursSpan = clock.querySelector('.hours');
const minutesSpan = clock.querySelector('.minutes');
const secondsSpan = clock.querySelector('.seconds');      

接下來,我們需要修改 updateClock 函數,使其隻更新數字。新的代碼是這樣的:

function updateClock(){
    const t = getTimeRemaining(endtime);


    daysSpan.innerHTML = t.days;
    hoursSpan.innerHTML = t.hours;
    minutesSpan.innerHTML = t.minutes;
    secondsSpan.innerHTML = t.seconds;


    ...
}      

7.3 添加前導0

現在時鐘不再每秒都在重建,我們還有另一件事要做:添加前導零。例如,不是讓時鐘顯示7秒,而是顯示07秒。一種簡單的方法是在一個數的開頭加上一串“0”,然後切掉最後兩個數字。

例如,要在“seconds”值上添加前導零,你可以更改以下設定:

secondsSpan.innerHTML = t.seconds;      

secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);      

如果你願意,你也可以在分鐘和小時的前面加零。如果你已經走到這一步,恭喜你!你的時鐘現在已經可以顯示了。

8、更進一步

以下示例示範了如何為某些用例擴充時鐘。它們都是基于上面的基本例子。

8.1 自動調節時鐘

假設我們想讓時鐘在特定的日子出現,而不是在其他的日子。例如,我們可能有一系列事件即将發生,而不希望每次都手動更新時鐘。以下是如何提前安排事情的方法。

通過在CSS中将其 display 屬性設定為 none 來隐藏時鐘,然後将以下内容添加到 initializeClock 函數中(以 var clock 開頭的行之後)。這将導緻隻有在調用 initializeClock 函數後才會顯示時鐘:

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 數組中的每個元素代表一個開始日期和一個結束日期。如上所述,它可以包含時間和時區,但我在這裡使用了普通的日期,以保持代碼的可讀性。

最後,當使用者加載頁面時,我們需要檢查是否在指定的時間範圍内。此代碼應替換先前對 initializeClock 函數的調用:

// 周遊schedule中的每個元素
schedule.forEach(([startDate, endDate]) => {
  // 以毫秒為機關放置日期以便于比較
  const startMs = Date.parse(startDate);
  const endMs = Date.parse(endDate);
  const currentMs = Date.parse(new Date());


  // 如果目前日期在開始日期和結束日期之間,則顯示時鐘
  if (endMs > currentMs && currentMs >= startMs ) {
    initializeClock('clockdiv', endDate);
  }
});      

現在,你可以提前安排你的時鐘,而不必手動更新它。如果你願意,你可以縮短代碼。為了便于閱讀,我把我的代碼寫得很啰嗦。

8.2 從使用者到達起将計時器設定為10分鐘

使用者到達或開始特定任務後,有必要在給定的時間内設定倒計時。我們将在此處将計時器設定為10分鐘,但是你可以使用任意時間。

我們需要做的就是用以下指令替換 deadline 變量:

const timeInMinutes = 10;
const currentTime = Date.parse(new Date());
const deadline = new Date(currentTime + timeInMinutes*60*1000);      

這段代碼以目前時間為基準,增加10分鐘。這些值将轉換為毫秒,是以可以将它們加在一起并變成新的截止日期。

現在我們有一個時鐘,從使用者到達時開始倒計時十分鐘,你可以自由發揮,嘗試不同的時間長度。

8.3 跨頁面保持時鐘進度

有時,除了目前頁面外,還需要保留時鐘狀态。如果我們想在整個網站上設定10分鐘的計時器,則我們不希望在使用者轉到其他頁面時重置該計時器。

一個解決方案是将時鐘的結束時間儲存在一個cookie中。這樣一來,導航到一個新的頁面就不會把結束時間重置到十分鐘以後。

這是邏輯:

  1. 如果Cookie中記錄了截止日期,使用該截止日期。
  2. 如果不存在Cookie,請設定一個新的截止日期并将其存儲在Cookie中。

要實作這一點,請使用以下指令替換 deadline 變量:

let deadline;


// 如果有一個名為myClock的cookie,則使用該值作為截止日期
if(document.cookie && document.cookie.match('myClock')){
  // 從Cookie擷取截止日期值
  deadline = document.cookie.match(/(^|;)myClock=([^;]+)/)[2];
} else {
  // 否則,請設定從現在開始10分鐘的截止日期,
  // 将其儲存在具有該名稱的cookie中


  // 建立從現在開始10分鐘的截止日期
  const timeInMinutes = 10;
  const currentTime = Date.parse(new Date());
  deadline = new Date(currentTime + timeInMinutes*60*1000);


  // 将截止日期存儲在cookie中以供将來引用
  document.cookie = 'myClock=' + deadline + '; path=/; domain=.yourdomain.com';
}      

需要注意的是,你需要将 .yourdomain.com 改為你的實際域名。

9、有關用戶端時間的重要警告

JavaScript日期和時間是從使用者的計算機上擷取的,這意味着使用者可以通過更改計算機上的時間來影響JavaScript時鐘。在大多數情況下,這并不重要,但在一些超級敏感的情況下,就需要從伺服器上擷取時間。可以使用一些Node.js或Ajax來完成,這兩者都超出了本教程的範圍。

從伺服器擷取時間後,我們可以使用本教程中的相同技術來使用它。

10、總結

在完成本文中的示例之後,你現在知道了如何使用幾行簡單的JavaScript代碼建立自己的倒計時計時器!我們已經了解了如何制作一個基本的倒計時時鐘并有效地顯示它。我們還介紹了添加一些有用的附加功能,包括日程安排、絕對時間與相對時間,以及在頁面和網站通路之間用cookie儲存狀态。

下一步是什麼?

試着添加一些創意風格,或者新的功能(比如暫停和恢複按鈕)。之後,如果你想出了任何很酷的時鐘例子,你想分享,讓我們在評論區見。

11、代碼

本示例代碼和示範位址:https://coding.zhangbing.site

18行JavaScript代碼建構一個倒數計時器

本文完~

繼續閱讀