完成切版之後,接下來要進入 JavaScript 實作。
在讓計時器動起來之前,先做一些準備:
建立與載入 all.js
DOM 元素選取與狀態變數初始化
寫出一個 時間格式化工具函式 :將「純秒數」轉換為「HH:MM:SS」
all.js先來建立一個 all.js,並記得在 HTML <body> 結束標籤前載入。
<!DOCTYPE html>
<head>...</head>
<html lang="zh-Hant">
<body>
<!-- 頁面 HTML 內容 -->
<!-- 載入Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<!-- 載入all.js -->
<script src="all.js"></script>
</body>
</html>
打開 all.js,先把畫面上需要操作的元素抓出來,並設定好紀錄計時狀態的變數:
// 1. 選取 DOM 元素
const timerDisplay = document.querySelector("#timer-display");
const btnStart = document.querySelector("#btn-start");
const btnGroupActive = document.querySelector("btn-group-active");
const btnPause = document.querySelector("#btn-pause");
const btnStop = document.querySelector("#btn-stop");
// 2. 宣告狀態變數
let timerInterval = null; // 用來存放 setInterval 回傳的 ID
let seconds = 0; // 紀錄累計的總秒數
let isRunning = false; // 紀錄目前是否正在計時
語法拆解const timerDisplay = document.querySelector("#timer-display");
const timerDisplay:宣告一個叫做 timerDisplay 的變數。
document:代表目前這個 HTML 網頁文件。
.querySelector("#timer-display"):從這個 HTML 網頁中,找出 id="timer-display" 的元素。
計時器核心累計的是 「總秒數」 (例如:3665 秒),但使用者畫面需要顯示「01:01:05」。
因此需要透過運算將秒數拆解成:
小時 (hrs):秒數 / 3600
分鐘 (mins):(秒數 % 3600) / 60
秒數 (secs):秒數 % 60
為了確保時間位數不足時會補 0(例如 5 秒顯示為 05),我們使用 ES6 的 String.prototype.padStart(目標長度, 填充字串) 方法:
// 時間格式化工具:秒數 -> HH:MM:SS
function formatTime(totalSeconds) {
const hrs = String(Math.floor(totalSeconds / 3600)).padStart(2, '0');
const mins = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0');
const secs = String(totalSeconds % 60).padStart(2, '0');
return `${hrs}:${mins}:${secs}`;
}
// 測試工具函式
console.log(formatTime(3665)); // 輸出:"01:01:05"
語法拆解計算小時:const hrs = String(Math.floor(totalSeconds / 3600)).padStart(2, "0");
totalSeconds / 3600 :一小時=3600秒
Math.floor():無條件捨去小數
String(...).padStart(2, "0"):轉成字串,如果字串不到2個字元,就在前面補"0"
個人筆記:
JS 內建物件 | 無條件捨去的小幫手:Math.floor() 使用指南
JS 內建物件 | 字串前補零與對齊:String.prototype.padStart() 使用指南
目前完成了 DOM 元素的選取、狀態變數的建立,並寫出了一個穩定運作的時間格式化函式。接下來將進入非同步計時的核心——setInterval 的運用。
在撰寫鐵人賽文章時,自己也把一些原本不太懂的部分寫成單獨的文章,如果有需要可以參考。
個人筆記:
JavaScript 基礎概念 | 什麼是 DOM ?如果網頁是一隻貓
JS DOM | 取得元素的方法:querySelector、querySelectorAll 與傳統選擇器
JS DOM | 選取多個元素時的集合:NodeList vs HTMLCollection 有何不同?
JavaScript | 乍看是貓,但其實不是我們說的那個貓?「真正的陣列(Array)」與「類陣列(Array-like Object)」差在哪?