今天要來寫個倒數計時器,這也象徵著鐵人賽的倒數。
HTML 架構如下:
<div class="timer">
<!-- 倒數計時的預設選項 -->
<div class="timer__controls">
<button data-time="20" class="timer__button">20 Secs</button>
<button data-time="300" class="timer__button">Work 5</button>
<button data-time="900" class="timer__button">Quick 15</button>
<button data-time="1200" class="timer__button">Snack 20</button>
<button data-time="3600" class="timer__button">Lunch Break</button>
<!-- 自訂時間選項 -->
<form name="customForm" id="custom">
<input type="text" name="minutes" placeholder="Enter Minutes">
</form>
</div>
<!-- 顯示倒數計時的區域-->
<div class="display">
<!-- 倒數計時讀秒 -->
<h1 class="display__time-left"></h1>
<!-- 顯示倒數計時終點 -->
<p class="display__end-time"></p>
</div>
</div>
該怎麼實現倒數的邏輯呢?先看以下程式碼。
const buttons = document.querySelectorAll('[data-time]')
function startTimer() {
const seconds = parseInt(this.dataset.time);
// 開始計時就是把預設秒數作為參數傳進計時器中
timer(seconds);
}
// 每個按鈕被按時,會開始計時
buttons.forEach(button => button.addEventListener('click', startTimer));
要倒數計時,首先要設定好碼錶。所以要讓「要倒數多久」做為參數傳入計時器。 HTML 裡面那些倒數計時設定鈕的 data-time
屬性中記錄著這些數字,當我們按按鈕時,就會觸發事件將時間傳進計時器。
自訂計時時間也是,把寫進 <input>
裡面的值轉換為秒數,傳進 timer()
計時器內。要存取表單的 DOM 來增加監聽器,若覺得 querySelector
太繁瑣,可以直接利用 document.[表格的 name]
來存取該表格。
document.customForm.addEventListener('submit', function(e) {
e.preventDefault();
const mins = this.minutes.value;
timer(mins * 60);
this.reset();
})
接下來就是計時器的核心:
function timer(sec) {
clearInterval(countdown)
// 現在時間與計時終了的時間
const now = Date.now();
const then = now + sec * 1000;
// 計時開始前顯示出初始設定
displayTimeLeft(sec);
displayEndTime(then);
// 開始計時
countdown = setInterval(() => {
const secLeft = Math.round((then - Date.now()) / 1000);
// 時間到就清除計時器並返回
if(secLeft < 0) {
clearInterval(countdown);
return;
}
// 還沒就顯示剩餘秒數
displayTimeLeft(secLeft);
}, 1000);
}
運作的邏輯像這樣:
setInterval
開始計時setInterval
會每秒中呼叫一次現在的正確時間,並且將其與最終時間相減,來算出還剩下多少秒setInterval
這個計時器取消掉,然後返回因為 setInterval
計時器不砍掉的話,會一直存在,若直接開啟下次計時,會變成有重複的計時器在進行動作,因此才這樣設計。
至於如何顯示時間,就跟 Day 2 邏輯差不多。程式碼如下:
// 用分 / 秒顯示剩下多久
function displayTimeLeft(sec) {
const minutes = Math.floor(sec / 60);
const remainderSecs = sec % 60;
const display = `${minutes}:${remainderSecs < 10 ? '0' : ''}${remainderSecs}`;
document.title = display;
timerDisplay.textContent = display;
}
// 用 時 / 分 / 秒 顯示何時計時終了
function displayEndTime(timestamp) {
const end = new Date(timestamp);
const hour = end.getHours();
const minutes = end.getMinutes();
endTime.textContent = `Be Back At ${hour > 12 ? hour - 12 : hour}:${minutes < 10 ? '0' : ''}${minutes}`;
}
以上就是 JS30 第二十九篇!