
英文 | 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 );
讓我們分解一下這裡發生的事情。
- 将毫秒除以1000可轉換為秒:(t/1000)
- 将總秒數除以60,然後取餘數。你不需要所有的秒,隻需要計算分鐘數後剩下的那些:(t/1000) % 60
- 四舍五入到最接近的整數。這是因為你需要完整的秒數,而不是幾分之一秒: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中。這樣一來,導航到一個新的頁面就不會把結束時間重置到十分鐘以後。
這是邏輯:
- 如果Cookie中記錄了截止日期,使用該截止日期。
- 如果不存在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
本文完~