有時候在生活中,你需要一個JavaScript倒計時時鍾,而不是一個末日裝置設備。不管你是否有一次約會,銷售、促銷、或者游戲,你可以受益於使用原生JavaScript構建一個時鍾,而不是拿到一個現成的插件。雖然有許多很棒的時鍾插件,但如果使用原生 JavaScript 實現,那你將得到以下好處:
- 代碼將是輕量級的,因為它沒有依賴關系。
- 你的網站會表現得更好,因為你不需要加載外部腳本和樣式表。
- 你將會有更高的可控性,因為你將按照想要的時鍾行為的方式來創建它(而不是找一個趨向你想法的插件)。
所以事不宜遲,以下是如何使用僅僅18行JavaScript代碼來做一個自己的倒計時時鍾。
基礎時鍾:倒計時到特定的日期或時間
以下是創建一個基礎時鍾的快速概要步驟:
- 設置一個有效的結束日期。
- 計算剩余時間。
- 將時間轉換成可用的格式。
- 輸出時鍾數據作為一個可重用的對象。
- 在頁面上顯示時鍾,並在它到達0時停止。
設置一個有效的結束日期
首先,你需要設置一個有效的結束日期。它是JavaScript Date.parse()方法能夠解析的任何格式的一個字符串。例如:
ISO 8601格式:
var deadline = ‘2015-12-31’;
短格式:
var deadline = ’31/12/2015′;
或者,長格式:
var deadline = ‘December 31 2015’;
這些格式都可以指定一個確切的時間(小時,分鍾和秒),以及時區(或者如果是ISO日期,則是UTC的偏移量)。例如:
var deadline = ‘December 31 2015 23:59:59 GMT+02:00’;
你可以在 此文閱讀更多關於JavaScript的日期格式化。
計算剩余時間
下一步是計算剩余時間。做到這一點,我們需要編寫一個函數,它接收一個代表給定結束時間的字符串(如上所述),並計算這個時間和當前時間的差值。代碼如下:
function getTimeRemaining(endtime){
var t = Date.parse(endtime) – Date.parse(new Date());
var seconds = Math.floor( (t/1000) % 60 );
var minutes = Math.floor( (t/1000/60) % 60 );
var hours = Math.floor( (t/(1000*60*60)) % 24 );
var days = Math.floor( t/(1000*60*60*24) );
return {
‘total’: t,
‘days’: days,
‘hours’: hours,
‘minutes’: minutes,
‘seconds’: seconds
};
}
首先,我們創建一個變量t,保存剩下的時間期限。Date.parse()函數是原生JavaScript,它將一個時間字符串轉換成以毫秒為單位的值。這讓我們可以將兩個時間相減,並獲得間隔時間。
var t = Date.parse(endtime) – Date.parse(new Date());
轉換時間為可用的格式
現在我們想把毫秒轉換成天、小時、分鍾、秒。讓我們以秒為例:
var seconds = Math.floor( (t/1000) % 60 );
讓我們解釋這是怎么回事。
- 毫秒除以1000轉換為秒:(t / 1000)
- 總秒除以60,獲取余數——你不想要所有的秒,只是(t / 1000)%60之后的分鍾剩余的秒數
- 將它取整,因為你想要完整的秒,而不是分數秒:Math.floor((t / 1000)% 60)
重復這個邏輯將秒轉換為分鍾、小時、天。
輸出時鍾數據作為一個可重用的對象
准備好天、小時、分鍾和秒,我們現在准備將數據作為一個可重用的對象返回:
return {
‘total’: t,
‘days’: days,
‘hours’: hours,
‘minutes’: minutes,
‘seconds’: seconds
};
該對象允許你調用函數,得到任何已計算的值。這里有一個如何得到剩余分鍾的例子:
getTimeRemaining(deadline).minutes
很方便,對嗎?
在頁面上顯示時鍾,並在它到達0時停止。
現在,我們有一個函數,它可以提取天、小時、分鍾和秒,我們可以構建時鍾了。首先,我們將創建以下HTML元素來存放我們的時鍾:
<div id=”clockdiv”></div>
然后我們將編寫一個函數,輸出時鍾數據到新div:
function initializeClock(id, endtime){
var clock = document.getElementById(id);
var timeinterval = setInterval(function(){
var 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。
- 如果剩余時間到達0,停止時鍾。
到這里,唯一剩下的步驟運行時鍾如下:
initializeClock(‘clockdiv’, deadline);
恭喜你!你現在有一個基本的時鍾,它只有短短18行JavaScript代碼。
優化時鍾顯示
給時鍾加樣式之前,我們需要完善一點的東西。
- 移除初始加載的延遲,這樣時鍾會立即出現。
- 為了讓時鍾腳本更有效率,不要不斷重建整個時鍾。
- 根據需要添加前綴0。
移除初始加載的延遲
在時鍾中,我們用setInterval每秒鍾更新顯示。大部分時間都很好,除了一開始的時候會有一秒鍾的延遲。為了消除這個延遲,我們將不得不在間隔開始前就更新時鍾。
要做到這一點,將傳遞給setInterval(它每秒鍾更新時鍾)的匿名函數遷移到一個獨立的函數,命名為updateClock。在setInterval外調用updateClock一次,然后在setInterval里面再次調用,這種方式,時鍾顯示的時候就沒有延遲。
在你的JavaScript中,替換:
var timeinterval = setInterval(function(){ … },1000);
為
function updateClock(){
var 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);
避免不斷重建時鍾
讓時鍾腳本更有效率,我們希望只更新時鍾的數據,而不是每一秒重建整個時鍾。實現這一目標的方法是,把每個數字嵌入到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變量定義的下面添加以下代碼
var daysSpan = clock.querySelector(‘.days’);
var hoursSpan = clock.querySelector(‘.hours’);
var minutesSpan = clock.querySelector(‘.minutes’);
var secondsSpan = clock.querySelector(‘.seconds’);
接下來,我們只需要改變updateClock函數來更新數據而不是重建整個時鍾。新代碼是這樣的:
function updateClock(){
var t = getTimeRemaining(endtime);
daysSpan.innerHTML = t.days;
hoursSpan.innerHTML = t.hours;
minutesSpan.innerHTML = t.minutes;
secondsSpan.innerHTML = t.seconds;
…
}
添加前導零
現在時鍾更新數據,而不是每一秒重建,我們還有一件事要做:添加前導零。例如,時鍾顯示7秒時,讓它顯示07。一個簡單的方法是在數字的開始處添加一個字符串“0”,然后獲取最后兩位數。
例如,為“seconds”添加一個前導零,你會這樣改變:
secondsSpan.innerHTML = t.seconds;
變成:
secondsSpan.innerHTML = (‘0’ + t.seconds).slice(-2);
如果你願意,你可以為minutes和hours添加前導零。如果你已經走了這么遠,那么恭喜你!你的時鍾可以顯示了。
注意:您可能需要點擊CodePen中的“Rerun”來啟動倒計時。
更進一步
下面的例子演示了如何為某些場景設計時鍾。他們都是基於上面的基礎例子。
自動安排時鍾
假設我們希望時鍾出現在特定的某些天。例如,我們可能會有一系列的事件出現,同時不想每次都手動更新時鍾。下面介紹如何提前進行規划安排。
在CSS中通過設置display屬性為none來隱藏時鍾。然后添加以下代碼到initializeClock函數(在var clock語句的后面)。這將導致時鍾只在initializeClock函數被調用顯示:
clock.style.display = ‘block’;
接下來,我們可以指定時鍾應該出現的時間段。這將替換deadline變量:
var schedule = [
[‘Jul 25 2015’, ‘Sept 20 2015’],
[‘Sept 21 2015’, ‘Jul 25 2016’],
[‘Jul 25 2016’, ‘Jul 25 2030’]
];
schedule數組中的每個元素代表了一個開始日期和結束日期。如上所述,可以包括時間和時區,但這里我用純日期來保持代碼的可讀性。
最后,當用戶加載頁面時,我們需要檢查,是否在指定的時間段內。這段代碼應該替換之前調用initializeClock函數的部分。
// iterate over each element in the schedule
for(var i=0; i&lt;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 &gt; currentMs &amp;&amp; currentMs &gt;= startMs ){
initializeClock(‘clockdiv’, endDate);
}
}
現在你可以提前安排你的時鍾,而不必手動更新它。你可以簡化代碼。我為了可讀性寫的有點詳細。
當用戶到達倒計時
有時有必要為一個用戶到達或開始一個特別任務的給定時間設置一個倒計時。這里我們將使用十分鍾,但是您可以使用任何你想要的時間。
所有我們需要做的是將deadline變量替換為:
var timeInMinutes = 10;
var currentTime = Date.parse(new Date());
var deadline = new Date(currentTime + timeInMinutes*60*1000);
這段代碼將當前時間增加了十分鍾。再轉換為毫秒,所以他們可以相加在一起,並轉換成一個新的截止日期。
現在我們有一個時鍾,在十分鍾用戶到達時倒計時。請隨便玩,嘗試不同的時間長度。
跨頁面保持時鍾
有時有必要不僅僅為當前頁面保持時鍾的狀態。例如,如果我們希望整個網站有一個十分鍾的倒計時,我們不希望每次用戶進入不同的頁面或每次用戶刷新頁面時重置時鍾。
一個解決方案是將時鍾的結束時間保存在cookie。這樣,導航到一個新的頁面不會重置結束時間為十分鍾。
邏輯是這樣的:
- 如果deadline記錄在一個cookie中,使用deadline。
- 如果cookie不存在,創建一個新的deadline並將它存儲在一個cookie中。
為了實現這一點,如下替換deadline變量:
// if there’s a cookie with the name myClock, use that value as the deadline
if(document.cookie &amp;&amp; document.cookie.match(‘myClock’)){
// get deadline value from cookie
var deadline = document.cookie.match(/(^|😉myClock=([^;]+)/)[2];
}
// otherwise, set a deadline 10 minutes from now and
// save it in a cookie with that name
else{
// create deadline 10 minutes from now
var timeInMinutes = 10;
var currentTime = Date.parse(new Date());
var deadline = new Date(currentTime + timeInMinutes*60*1000);
// store deadline in cookie for future reference
document.cookie = ‘myClock=’ + deadline + ‘; path=/; domain=.yourdomain.com’;
}
這段代碼使用了 cookies 和正則表達式,這兩部分是分開的。出於這個原因,我不會講太多的細節。需要注意的一個重要的事情是,你需要將.yourdomain.com替換成真實的域。如果你對此有任何問題,在評論中讓我知道。
關於客戶端時間的一個重要的警告
JavaScript的日期和時間從用戶的計算機上獲取。這意味着用戶可以通過改變機器的時間來影響一個JavaScript時鍾。在大多數情況下,這並不重要,但是對於一些超級敏感的情況,有必要從服務器獲取時間。這可以使用PHP或Ajax,兩者都是超出了本教程的范圍。
在任何情況下,從服務器獲取時間后,我們可以使用和本教程相同的客戶端技術來使用它。
總結
我們已經介紹了如何做一個基礎的倒計時時鍾和進行有效的顯示。我們也學習了計划時鍾,絕對與相對時間,跨頁面保持時鍾的狀態。
下一步?
玩時鍾代碼。嘗試添加一些有創意的樣式,或新功能(如暫停和恢復按鈕)。如果你想出任何酷炫時鍾的例子,且你想要和我們分享,或者對以上內容有任何疑問,請在評論中讓我知道。