2026年11月1日 星期日

JavaScript 入門教學(二):DOM 操作與事件處理

上一篇我們學會了變數、函式與流程控制,但程式只在 Console 裡執行,網頁本身並不會有任何變化。這一篇要學的是 JavaScript 與網頁互動的關鍵:DOM 操作與事件處理。學會之後,你就能做出按鈕點擊、表單驗證、動態新增內容等功能。

一、什麼是 DOM?

DOM(Document Object Model,文件物件模型)是瀏覽器把 HTML 轉換成的「樹狀結構」。每一個標籤都是樹上的一個節點,JavaScript 可以透過 DOM 讀取或修改網頁的內容、樣式與結構。

document
 └─ html
     ├─ head
     │   └─ title
     └─ body
         ├─ h1
         └─ p

在 JavaScript 中,document 物件就是進入這棵樹的入口。

二、選取元素

要操作元素,必須先「找到」它。現代寫法建議使用 querySelector 與 querySelectorAll,語法與 CSS 選擇器相同:

// 選取第一個符合的元素
const title = document.querySelector("h1");
const box   = document.querySelector("#box");        // 以 id 選取
const item  = document.querySelector(".item");       // 以 class 選取

// 選取所有符合的元素(回傳 NodeList,可用 for...of 或 forEach 走訪)
const items = document.querySelectorAll(".item");
items.forEach(el => console.log(el.textContent));
方法 回傳結果
querySelector(選擇器) 第一個符合的元素,找不到為 null
querySelectorAll(選擇器) 所有符合的元素(NodeList)
getElementById(id) 指定 id 的元素

三、修改內容、屬性與樣式

const title = document.querySelector("h1");

// 1. 修改文字內容
title.textContent = "新的標題";

// 2. 修改 HTML 內容(注意:不要放入使用者輸入的內容,有安全風險)
title.innerHTML = "新的 <em>標題</em>";

// 3. 修改屬性
const img = document.querySelector("img");
img.setAttribute("src", "photo.jpg");
img.alt = "風景照片";

// 4. 修改樣式
title.style.color = "tomato";
title.style.fontSize = "32px";

// 5. 切換 class(最推薦的樣式控制方式)
title.classList.add("active");
title.classList.remove("active");
title.classList.toggle("active");   // 有就移除,沒有就加入

小提醒:需要大量變更樣式時,建議在 CSS 寫好 class,再用 classList 切換,程式碼會比直接改 style 更好維護。

四、建立與刪除元素

const list = document.querySelector("#list");

// 建立新元素
const li = document.createElement("li");
li.textContent = "新的項目";

// 加到清單最後面
list.appendChild(li);

// 加到最前面
list.prepend(li);

// 刪除元素
li.remove();

五、事件處理

「事件」是使用者或瀏覽器所發生的動作,例如點擊、輸入、滑鼠移動、頁面載入完成等。我們使用 addEventListener 來「監聽」事件:

const btn = document.querySelector("#btn");

btn.addEventListener("click", function (event) {
  console.log("按鈕被點擊了!");
  console.log(event.target);   // 觸發事件的元素
});

常見的事件類型:

事件 觸發時機
click 滑鼠點擊
input 輸入框內容改變(每打一個字就觸發)
submit 表單送出
keydown 按下鍵盤按鍵
mouseover 滑鼠移入元素
DOMContentLoaded HTML 解析完成

阻止預設行為

表單送出時,瀏覽器預設會重新整理頁面。若想自行處理,要使用 preventDefault():

const form = document.querySelector("#myForm");

form.addEventListener("submit", function (e) {
  e.preventDefault();   // 阻止頁面重新整理
  console.log("表單已攔截,由 JavaScript 處理");
});

事件委派(Event Delegation)

如果清單中有很多項目,逐一綁定事件既麻煩,新增的項目也不會有事件。更好的做法是把事件綁在「父元素」上,利用事件會往上冒泡的特性來判斷是哪個子元素被點擊:

const list = document.querySelector("#list");

list.addEventListener("click", function (e) {
  if (e.target.tagName === "LI") {
    e.target.classList.toggle("done");
  }
});

六、綜合範例:待辦事項清單

把前面學到的整合起來,完成一個簡單的待辦清單。將下列程式碼存成 todo.html,用瀏覽器開啟即可測試:

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="UTF-8">
  <title>待辦清單</title>
  <style>
    .done { text-decoration: line-through; color: gray; }
    li { cursor: pointer; margin: 6px 0; }
  </style>
</head>
<body>
  <h1>我的待辦清單</h1>
  <form id="todoForm">
    <input type="text" id="todoInput" placeholder="輸入待辦事項" required>
    <button type="submit">新增</button>
  </form>
  <ul id="todoList"></ul>

  <script>
    const form  = document.querySelector("#todoForm");
    const input = document.querySelector("#todoInput");
    const list  = document.querySelector("#todoList");

    // 新增項目
    form.addEventListener("submit", function (e) {
      e.preventDefault();
      const text = input.value.trim();
      if (text === "") return;

      const li = document.createElement("li");
      li.textContent = text;
      list.appendChild(li);

      input.value = "";
      input.focus();
    });

    // 事件委派:點一下標示完成,連點兩下刪除
    list.addEventListener("click", function (e) {
      if (e.target.tagName === "LI") {
        e.target.classList.toggle("done");
      }
    });

    list.addEventListener("dblclick", function (e) {
      if (e.target.tagName === "LI") {
        e.target.remove();
      }
    });
  </script>
</body>
</html>

七、常見錯誤與提醒

  • 找不到元素(null):如果 <script> 寫在 <head>,執行時 HTML 還沒載入。解法是把 script 放在 </body> 前,或加上 defer 屬性。
  • innerHTML 的安全問題:直接把使用者輸入的內容放進 innerHTML 可能造成 XSS 攻擊,一般文字請使用 textContent。
  • querySelectorAll 的結果:它回傳的是 NodeList,不是真正的陣列,需要用 Array.from() 轉換後才能使用 map、filter。

八、練習題

  1. 製作一個按鈕,每點一次,畫面上的數字就加 1。
  2. 製作一個「切換深色/淺色模式」的按鈕,使用 classList.toggle 完成。
  3. 在待辦清單範例中,加入「清除全部」按鈕。
  4. 製作一個輸入框,並在下方即時顯示已輸入的字數(提示:使用 input 事件)。

結語

這篇介紹了如何選取元素、修改內容與樣式、動態建立元素,以及用事件讓網頁與使用者互動。DOM 與事件是前端開發的核心,建議多動手練習。下一篇將介紹 非同步程式設計(Promise、async/await 與 fetch),讓你的網頁能向伺服器取得資料。如果有任何問題,歡迎在下方留言討論!

沒有留言:

張貼留言