iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0
JavaScript

解決學了JavaScript不知道能做什麼:用DOM操作打造實用網頁效果 系列 第 2

打造網頁的「夜間/日間模式切換器」

  • 分享至 

  • xImage
  •  

剛學完 JS 的變數和迴圈,打開空白的 HTML 卻不知道從何下手嗎?別擔心!今天我們用大家最常用的功能——「夜間模式切換」,教你使用 DOM 的第一步。

核心觀念:什麼是 classList.toggle

在網頁開發中,我們很少直接用 JS 修改單一的顏色或字體,而是會先在 CSS 寫好兩套樣式(例如 .dark-mode),再透過 JS 來控制 Class 的「存在與否」。

element.classList.toggle('class-name') 就像一個燈光開關:沒有這個 Class 就幫你加上,有了就幫你移除。

第一課:打造網頁的「夜間/日間模式切換器」

我們直接從非常實用的功能開始!很多網站都有「暗色模式」,其實背後的核心原理就是用 JS 切換 CSS 的 Class(類別)

步驟 1:建立網頁骨架 (HTML)

請在你的電腦上開一個 index.html 檔案,貼上以下內容:

<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>夜間模式切換</title>
  <style>
    /* 預設的日間模式(白底黑字) */
    body {
      background-color: #ffffff;
      color: #333333;
      transition: all 0.3s ease; /* 讓顏色切換時有平滑的過渡動畫 */
      font-family: sans-serif;
      padding: 50px;
    }

    /* 夜間模式的樣式(黑底白字) */
    body.dark-mode {
      background-color: #121212;
      color: #ffffff;
    }

    button {
      padding: 10px 20px;
      font-size: 16px;
      cursor: pointer;
    }
  </style>
</head>
<body>

  <h1>Hello! 歡迎來到我的 DOM 教學</h1>
  <p>點擊下方按鈕來切換日間與夜間模式吧!</p>
  
  <button id="themeBtn">切換模式</button>

  <script>
    // 我們的 JS 程式碼會寫在這裡
  </script>
</body>
</html>

步驟 2:加入 JavaScript DOM 操作

請把下面的 JS 程式碼放到 <script> 標籤裡面:

// 1. 抓取按鈕元素
const btn = document.getElementById("themeBtn");

// 2. 為按鈕監聽「點擊 (click)」事件
btn.addEventListener("click", function() {
  // 3. 切換 body 的 dark-mode 類別
  document.body.classList.toggle("dark-mode");
});

觀念拆解:這三行程式碼在幹嘛?

  1. document.getElementById("themeBtn"):拿到按鈕的控制權。
  2. addEventListener("click", ...):像是一個哨兵,專門在按鈕旁邊蹲點,只要使用者「點擊」,它就會執行後面的動作。
  3. classList.toggle("dark-mode"):這是最神奇的地方!
    • toggle 的意思是「開關」。
    • 如果 body 目前沒有 dark-mode 這個 class,它就加上去(變成黑底)。
    • 如果已經有了,它就拿掉(變回白底)。

函式說明

1. document.getElementById('themeBtn')

為什麼選用這個函式?

因為我們的 HTML 中,按鈕設定了 id="themeBtn"。當目標對象有標示 ID 時,getElementById 是瀏覽器效能最好的抓取方式。

這個函式在幹嘛?

  • 語意拆解document(整張網頁)+ get(取得)+ Element(元素)+ By Id( ID)。
  • 功能:告訴瀏覽器:「請幫我在整頁 HTML 當中,找到第一個 id 叫作 themeBtn 的 HTML 標籤,並把它拿給我控制。」

有沒有其他替代方案?

  • 方案 A:document.querySelector('#themeBtn')
    • 簡介:使用 CSS 選擇器語法(# 代表 ID,. 代表 Class)。
    • 比較querySelector 功能非常強大,什麼都能抓( Class、Tag、ID 等),但如果是單純抓 ID,getElementById 的執行速度比它快一些,語意也更直接。
  • 方案 B:document.getElementsByClassName('btn')
    • 簡介:透過 Class 名稱抓取。
    • 比較:它回傳的是一個「元素陣列」,即使只有一個按鈕,你還是要寫 [0] 才能拿到第一個元素(例如 [0]),寫起來比較麻煩。

最後選擇結論:抓特定唯一的 ID 時,首選 getElementById

2. btn.addEventListener('click', function)

為什麼選用這個函式?

因為這是網頁開發中最標準、最彈性的事件監聽方式。它能幫元素貼上一張「告示牌」,只要指定的事件(例如點擊)發生,就會自動執行任務。

這個函式在幹嘛?

  • 語意拆解add(新增)+ Event(事件)+ Listener(監聽器)。
  • 第一個參數 'click':指定要監聽什麼動作。
  • 第二個參數 function() { ... }:點擊發生時,要執行的動作內容。

有沒有其他替代方案?

  • 方案 A:在 HTML 直接寫 onclick="myFunction()"
    • 簡介:舊式的寫法,直接把 JS 邏輯綁在 HTML 標籤上。
    • 比較:這樣會把「網頁骨架(HTML)」跟「動作邏輯(JS)」混在一起,程式碼多了會非常難維護。
  • 方案 B:在 JS 寫 btn.onclick = function() { ... }
    • 簡介:直接修改 DOM 物件的 onclick 屬性。
    • 比較:缺點是同一個按鈕只能綁定一個動作。如果你寫了第二次 btn.onclick,第一次寫的動作就會被覆蓋掉;而 addEventListener 可以針對同一個按鈕綁定無限多個不同的任務。

最後選擇結論:因為addEventListener 遵循「關注點分離」原則(就是HTML 與 JS 分開),且支援綁定多個事件。

3. element.classList.toggle('dark-mode')

為什麼選用這個函式?

因為這是實現「開關切換」寫法最簡潔的函式,不用手動去寫 if...else 判斷。

這個函式在幹嘛?

  • 語意拆解classList(元素的 Class 列表清單)+ toggle(切換)。
  • 動作機制:檢查該元素身上有沒有 'dark-mode' 這個 Class。
    • 如果沒有 $\rightarrow$ 自動幫你加上。
    • 如果已有 $\rightarrow$ 自動幫你拔除。

有沒有其他替代方案?

  • 方案 A:用 if...else 結合 contains 手動判斷JavaScript

    if (document.body.classList.contains("dark-mode")) {
      document.body.classList.remove("dark-mode");
    } else {
      document.body.classList.add("dark-mode");
    }
    
    • 比較:邏輯一樣,但你需要寫 5 行程式碼,而 toggle 只需 1 行。
  • 方案 B:直接修改內聯樣式 element.style.backgroundColor = 'black'

    • 簡介:用 JS 直接改 style 屬性。
    • 比較:不推薦!因為如果未來要改夜間模式的字體顏色、邊框、圖片亮度,你就得寫幾十行 JS 來改每一個樣式;改用 classList 的話,JS 只需要切換 Class,所有樣式全部交給 CSS 管理,維護比較輕鬆。

最後選擇結論classList.toggle 完美體現了「JS 只管狀態邏輯,CSS 負責視覺外觀」的分工。

下集預告: Day 3:顯示/隱藏密碼與明暗文切換


上一篇
【第一課】解決學了 JavaScript 卻做不出東西:用 DOM 操作打造 30 天實用網頁效果
系列文
解決學了JavaScript不知道能做什麼:用DOM操作打造實用網頁效果 2
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言