前兩天的實作中,成功地讓計時器開始動起來,但當按下開始計時後,按鈕的UI卻沒有變化,今天就要來完成這一部分:點擊「開始」時動態隱藏/顯示按鈕,並實現「暫停/繼續」與「結束」功能。
在切版時,針對計時中的按鈕(暫停/結束)使用了 Bootstrap 的 d-none (display: none) 先隱藏起來了。
因此當計時開始時,我們要把 #btn-start 加上 d-none 隱藏,並將包含暫停與結束按鈕的 #btn-group-active 移除 d-none 顯示出來:
<!-- 計時控制按鈕區塊 -->
<div id="timer-controls" class="mb-3">
<!-- 狀態 A:未計時(預設顯示) -->
<button
id="btn-start"
type="button"
class="btn btn-primary btn-lg px-4"
>
<i class="bi bi-play-fill me-1"></i>開始計時
</button>
<!-- 狀態 B:計時中(預設隱藏) -->
<div id="btn-group-active" class="d-none">
<button
id="btn-pause"
type="button"
class="btn btn-warning btn-lg me-2"
>
<i class="bi bi-pause-fill me-1"></i>暫停
</button>
<button
id="btn-stop"
type="button"
class="btn btn-danger btn-lg"
>
<i class="bi bi-stop-fill me-1"></i>結束
</button>
</div>
</div>
function startTimer() {
if (isRunning) return;
isRunning = true;
// UI 切換:隱藏「開始」,顯示「暫停 / 結束」按鈕組
btnStart.classList.add('d-none');
btnGroupActive.classList.remove('d-none');
timerInterval = setInterval(() => {
seconds++;
timerDisplay.textContent = formatTime(seconds);
}, 1000);
}
同一個暫停按鈕,在計時中點擊會變為「繼續」,再次點擊又會恢復為「暫停」。可以利用 isRunning 狀態來做判斷:
// 暫停 / 繼續切換函式
function togglePauseTimer() {
if (isRunning) {
// 進入暫停狀態:清除定時器
clearInterval(timerInterval);
isRunning = false;
// 更新 UI 樣式為「繼續」
btnPause.innerHTML = '<i class="bi bi-play-fill me-1"></i>繼續';
btnPause.classList.replace('btn-warning', 'btn-success');
} else {
// 恢復計時狀態:重新啟動定時器
isRunning = true;
// 更新 UI 樣式為「暫停」
btnPause.innerHTML = '<i class="bi bi-pause-fill me-1"></i>暫停';
btnPause.classList.replace('btn-success', 'btn-warning');
timerInterval = setInterval(() => {
seconds++;
timerDisplay.textContent = formatTime(seconds);
}, 1000);
}
}
按下「結束」時,必須徹底清空定時器、資料歸零,並把 UI 恢復成最初的樣子:
// 結束計時函式
function stopTimer() {
// 1. 清除定時器與狀態重置
clearInterval(timerInterval);
timerInterval = null;
isRunning = false;
seconds = 0;
// 2. 顯示文字與暫停按鈕樣式復原
timerDisplay.textContent = '00:00:00';
btnPause.innerHTML = '<i class="bi bi-pause-fill me-1"></i>暫停';
btnPause.classList.replace('btn-success', 'btn-warning');
// 3. UI 切換:隱藏暫停/結束組,顯示開始按鈕
btnGroupActive.classList.add('d-none');
btnStart.classList.remove('d-none');
}
// 監聽事件綁定
btnPause.addEventListener('click', togglePauseTimer);
btnStop.addEventListener('click', stopTimer);
(今日成果)
經過這三天的拆解實作,我們從資料處理、非同步計時,到最後的 DOM 互動與 UI 狀態切換,打造出了一個功能齊備、體驗順暢的計時器核心模組。