18 行 JS 程式碼編一個倒時器

熊哥club發表於2016-08-04

有時候在生活中,你需要一個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 );

讓我們解釋這是怎麼回事。

  1. 毫秒除以1000轉換為秒:(t / 1000)
  2. 總秒除以60,獲取餘數——你不想要所有的秒,只是(t / 1000)%60之後的分鐘剩餘的秒數
  3. 將它取整,因為你想要完整的秒,而不是分數秒: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 + ‘&lt;br&gt;’ +

		‘hours: ‘+ t.hours + ‘&lt;br&gt;’ +

		‘minutes: ‘ + t.minutes + ‘&lt;br&gt;’ +

		‘seconds: ‘ + t.seconds;

		if(t.total&lt;=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 + ‘&lt;br&gt;’ +

	‘hours: ‘+ t.hours + ‘&lt;br&gt;’ +

	‘minutes: ‘ + t.minutes + ‘&lt;br&gt;’ +

	‘seconds: ‘ + t.seconds;

	if(t.total&gt;=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&amp;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 &amp;gt; currentMs &amp;amp;&amp;amp; currentMs &amp;gt;= startMs ){

		initializeClock(‘clockdiv’, endDate);

	}

}

現在你可以提前安排你的時鐘,而不必手動更新它。你可以簡化程式碼。我為了可讀性寫的有點詳細。

當使用者到達倒數計時

有時有必要為一個使用者到達或開始一個特別任務的給定時間設定一個倒數計時。這裡我們將使用十分鐘,但是您可以使用任何你想要的時間。

所有我們需要做的是將deadline變數替換為:

var timeInMinutes = 10;

var currentTime = Date.parse(new Date());

var deadline = new Date(currentTime + timeInMinutes*60*1000);

這段程式碼將當前時間增加了十分鐘。再轉換為毫秒,所以他們可以相加在一起,並轉換成一個新的截止日期。

現在我們有一個時鐘,在十分鐘使用者到達時倒數計時。請隨便玩,嘗試不同的時間長度。

跨頁面保持時鐘

有時有必要不僅僅為當前頁面保持時鐘的狀態。例如,如果我們希望整個網站有一個十分鐘的倒數計時,我們不希望每次使用者進入不同的頁面或每次使用者重新整理頁面時重置時鐘。

一個解決方案是將時鐘的結束時間儲存在cookie。這樣,導航到一個新的頁面不會重置結束時間為十分鐘。

邏輯是這樣的:

  1. 如果deadline記錄在一個cookie中,使用deadline。
  2. 如果cookie不存在,建立一個新的deadline並將它儲存在一個cookie中。

為了實現這一點,如下替換deadline變數:

// if there’s a cookie with the name myClock, use that value as the deadline

if(document.cookie &amp;amp;&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,兩者都是超出了本教程的範圍。

在任何情況下,從伺服器獲取時間後,我們可以使用和本教程相同的客戶端技術來使用它。

總結

我們已經介紹瞭如何做一個基礎的倒數計時時鐘和進行有效的顯示。我們也學習了計劃時鐘,絕對與相對時間,跨頁面保持時鐘的狀態。

下一步?

玩時鐘程式碼。嘗試新增一些有創意的樣式,或新功能(如暫停和恢復按鈕)。如果你想出任何酷炫時鐘的例子,且你想要和我們分享,或者對以上內容有任何疑問,請在評論中讓我知道。

相關文章