Chapter 05 / JavaScript + DOM + CSS

讓網頁從靜態畫面變成會回應使用者的互動系統

HTML 提供結構,CSS 負責樣式,而 JavaScript 會在使用者操作時讀取 DOM、改變內容、切換 class 或更新 CSS 變數。 理解這條鏈路,才算真正學會前端互動。 這也是之後閱讀 React、Vue、Angular 等框架時最重要的底層基礎。

Why:為什麼學完 HTML / CSS 之後要接著學 DOM?

如果 HTML 與 CSS 只能決定「一開始長什麼樣子」,那 JavaScript 與 DOM 就負責「使用者操作之後會發生什麼事」。 例如按鈕被點擊後改字、表單輸入後即時預覽、卡片被選取後套用高亮樣式,背後都不是新畫一張畫面,而是改變既有 DOM 節點與 CSS 狀態。

HTML:放入元素

先決定頁面裡有哪些標題、按鈕、清單、卡片與表單欄位。

CSS:定義外觀

設定顏色、間距、字體、版面與不同狀態時的外觀規則。

DOM:可被操作的結構

瀏覽器把 HTML 解析成節點樹,JavaScript 才有東西可以選取與修改。

JavaScript:互動邏輯

監聽事件、執行規則、改動 DOM 與 class,讓畫面隨狀態改變。

What:DOM、CSS 與畫面更新流程

flowchart LR A[HTML 原始碼] --> B[Browser 建立 DOM] C[CSS 規則] --> D[Browser 建立樣式規則] B --> E[畫面初始渲染] D --> E F[使用者事件 click input submit] --> G[JavaScript 事件處理器] G --> H[修改文字 / 屬性 / class / style] H --> I[重新計算樣式與畫面] I --> J[看到新的結果]
概念 它是什麼 常見操作 你會看到的效果
DOM 瀏覽器把 HTML 解析後建立的節點樹 querySelector()textContentappend() 內容改變、節點新增或刪除
CSS 規則 決定元素不同狀態的外觀 classList.toggle()style.setProperty() 顏色、間距、版面、動畫狀態改變
事件 瀏覽器通知「某件事發生了」 addEventListener("click", ...) 點擊、輸入、送出等操作可以觸發程式
重新渲染 瀏覽器根據新狀態更新畫面 通常由前面三者連動產生 畫面看起來立即變化
重點: JavaScript 並不是直接「畫圖」,而是透過 DOM 與 CSS 規則改變瀏覽器要呈現的狀態。

先看懂:HTML 原始碼、DOM 樹與畫面不是同一件事

1. HTML 原始碼

<h1>Hello</h1>
<p>這是一段說明。</p>

這是你存在檔案裡的文字內容。

2. DOM 樹

document
└─ body
   ├─ h1
   └─ p

瀏覽器把 HTML 解析後,會在記憶體裡建立節點關係。

3. 畫面結果

你真正看到的是瀏覽器根據 DOM + CSS 渲染出來的畫面。

JavaScript 改的是 DOM 狀態,不是直接改硬碟裡的 HTML 檔。

關鍵差異: HTML 檔是磁碟上的文字,DOM 是瀏覽器記憶體裡的節點樹。當你用 JavaScript 改 textContentclassList,改的是 DOM;重新整理頁面後,瀏覽器會依原始 HTML 重新建立 DOM。

迷你實驗:為什麼重新整理後會恢復原狀?

實驗步驟

  • 先看下面 Example 1 的結果頁籤。
  • 點一次按鈕,觀察文字改變。
  • 重新整理頁面或重新載入 iframe,看看文字是否恢復。

你會學到什麼

  • JavaScript 改變的是「目前這次載入的 DOM」。
  • 除非你把資料存起來,否則重整後會回到原始 HTML 的狀態。
  • 這也是前端狀態管理與資料持久化為什麼重要的起點。

How:最常用的 DOM API 與樣式控制方式

API / 寫法 用途 典型情境 說明
document.getElementById("id") 用 id 取得單一節點 表單欄位、重要按鈕 速度快,但只能找 id。
document.querySelector("selector") 用 CSS selector 取得第一個符合的節點 找 class、屬性、巢狀節點 最常用,也最接近 CSS 思維。
document.querySelectorAll("selector") 取得多個節點 一組按鈕、清單項目 通常搭配 forEach() 使用。
element.textContent = "..." 改變純文字內容 提示訊息、計數器、標題更新 安全、直覺,優先於 innerHTML
element.innerHTML = "..." 插入 HTML 片段 真的需要插入結構化標籤時 要留意安全性與 XSS 風險。
element.classList.add/remove/toggle() 切換 CSS class 深色模式、選取狀態、顯示 / 隱藏 最推薦的樣式切換方式。
element.style.property = value 直接改 inline style 少量動態樣式 適合簡單情況,但大型專案通常 prefer class。
element.addEventListener(type, handler) 監聽事件 click、input、submit、change 所有互動幾乎都從這裡開始。
document.createElement() + append() 建立新節點並加入 DOM 新增清單、卡片、訊息列 讓內容可以由程式動態擴充。
安全提醒: 如果只是更新文字,請優先用 textContent。 只有在你確定內容安全,而且真的需要插入標籤時,才使用 innerHTML

Example 1:點擊按鈕後更新 DOM 文字

最基本的事件 + DOM 更新

請試著在結果頁籤點按鈕,再重新整理頁面觀察,這會幫你理解 DOM 修改與原始 HTML 的差異。

<button id="hello-btn">點我</button>
<p id="message">尚未互動</p>

<script>
  const btn = document.querySelector("#hello-btn");
  const message = document.querySelector("#message");

  btn.addEventListener("click", () => {
    message.textContent = "按鈕已被點擊,DOM 已更新。";
  });
</script>
  • querySelector() 先找到按鈕與段落節點。
  • addEventListener("click", ...) 代表「有人點按鈕時,執行這段程式」。
  • textContent 會直接改變段落中的文字內容。
  • 重新整理頁面後,文字會回到原本狀態,因為 DOM 會依原始 HTML 重新建立。

Example 2:用 classList 切換 CSS 樣式

把「邏輯」與「外觀」分開

JavaScript 不需要自己決定每個顏色值,只要切換 class,CSS 就能接手完成樣式變化。

<div class="card" id="lesson-card">
  DOM 互動練習卡片
</div>
<button id="toggle-style">切換重點樣式</button>

<style>
  .card {
    padding: 18px;
    border-radius: 16px;
    background: #e2e8f0;
    transition: all .2s ease;
  }

  .card.is-highlight {
    background: #dbeafe;
    color: #1d4ed8;
    transform: translateY(-4px);
    box-shadow: 0 12px 24px rgba(37, 99, 235, .18);
  }
</style>

<script>
  const card = document.querySelector("#lesson-card");
  const toggleButton = document.querySelector("#toggle-style");

  toggleButton.addEventListener("click", () => {
    card.classList.toggle("is-highlight");
  });
</script>
  • JavaScript 只負責切換 is-highlight 這個 class。
  • 實際的顏色、陰影、位移與過渡效果都交給 CSS 控制。
  • 這種分工比直接在 JavaScript 裡一條一條改 style 更容易維護。

Example 3:用 JavaScript 改變 CSS 變數

把互動值交給 CSS Custom Properties

如果想要讓主題色、圓角或間距隨使用者操作變化,CSS 變數會非常好用。

<style>
  :root {
    --accent-hue: 220;
  }

  .demo-panel {
    padding: 18px;
    border-radius: 18px;
    background: hsl(var(--accent-hue) 95% 96%);
    border: 2px solid hsl(var(--accent-hue) 70% 45%);
    color: hsl(var(--accent-hue) 70% 28%);
  }
</style>

<input id="accent" type="range" min="180" max="340" value="220">
<div class="demo-panel">主題卡片會跟著顏色改變</div>

<script>
  const accent = document.querySelector("#accent");

  accent.addEventListener("input", (event) => {
    document.documentElement.style.setProperty("--accent-hue", event.target.value);
  });
</script>
  • CSS 變數讓樣式值可以被集中管理。
  • style.setProperty() 能直接改寫變數值,影響所有使用該變數的地方。
  • 這種方法很適合做主題色、深色模式或互動式控制面板。

常見事件與互動情境

事件類型 常見綁定元素 用途 範例
click 按鈕、連結、卡片 處理點擊行為 顯示資訊、開關區塊、切換 class
input 文字欄、range、textarea 即時回應輸入 即時搜尋、主題調整、字數統計
change select、checkbox、radio 值確定改變後才觸發 篩選器、設定選單
submit form 處理表單送出 驗證輸入、送到 API
keydown 整份文件、輸入欄 偵測鍵盤操作 快捷鍵、Enter 送出、Esc 關閉

Troubleshooting:為什麼 JavaScript 改了卻沒反應?

問題 1:選不到元素

  • 先確認 selector 是否真的對應到 HTML。
  • 檢查 id 與 class 是否拼錯。
  • 如果腳本在 HTML 前面執行,節點可能尚未建立。

問題 2:事件沒有綁上去

  • 確認有沒有寫 addEventListener()
  • 確認事件類型是否正確,例如按鈕常用 click
  • 若是表單,必要時用 event.preventDefault() 避免整頁重整。

問題 3:class 切了但畫面沒變

  • 確認 CSS 裡真的有寫對應的 class 規則。
  • 檢查是否被更高優先權的樣式覆蓋。
  • 先用簡單明顯的背景色做測試最容易除錯。

問題 4:腳本執行時機太早

  • 建議在外部 script 加上 defer
  • 或把程式放在 DOMContentLoaded 事件中。
  • 這樣可確保 DOM 建好後才開始操作。

從原生 DOM API 走向常用 Library / Toolkit

當你已經理解 querySelector()addEventListener()classListfetch(), 下一步就比較容易看懂各種 JavaScript 套件到底在幫你省什麼工。 它們通常不是取代原生能力,而是把常見任務包裝得更快、更一致、更容易維護。

工具 / 類型 它在幫你做什麼 典型使用情境
jQuery 簡化 DOM 操作、事件綁定與 AJAX 舊專案維護、快速操作頁面元素
Axios 更一致地發送 HTTP 請求 前端呼叫 API、處理攔截器與錯誤格式
Lodash 整理陣列、物件與資料轉換 資料清理、排序、去重複、節流
Alpine.js 用接近 HTML 的方式做輕量互動 選單、摺疊區、簡單狀態切換
Bootstrap 提供現成 UI 元件、版型與部分互動元件 快速建立後台介面、表單與響應式版面
Chart.js 快速把資料畫成圖表 儀表板、成績分析、資料視覺化
學習建議: 先把原生 DOM 與事件觀念打穩,再學 library / toolkit,才不會只記得套件寫法卻不知道底層發生什麼事。 如果你想把 JavaScript 的發展歷史、常用套件、生態與後端角色一次串起來,接著可看 第 08 章:JavaScript 全貌;如果你想看 jQuery 如何把這些原生操作包裝成更短的寫法,也可以接著讀 第 09 章:jQuery 詳解;若要把 fetch()、API 與局部更新的原理一次補清楚,可再讀 第 10 章:AJAX 原理

Practice:可以讓學生實作什麼?

練習 1:課程卡片高亮

做三張課程卡片,點選哪一張,就把那一張加上高亮 class。

練習 2:即時輸入預覽

讓使用者在 input 輸入課程名稱,旁邊的預覽卡片即時同步文字。

練習 3:主題切換器

用 checkbox 或 button 切換深色 / 淺色模式,觀察 class 與 CSS 變數如何配合。

Summary:本章結論

  • JavaScript 的核心工作之一,是回應事件並操作 DOM。
  • HTML 原始碼、DOM 樹與畫面結果不是同一件事;JavaScript 改的是瀏覽器記憶體中的 DOM。
  • 改變畫面時,最推薦的做法通常是切換 class,讓 CSS 負責樣式細節。
  • 重新整理後 DOM 會重新建立,因此理解 DOM、事件與 CSS 狀態的分工,會直接影響你之後是否能順利學會框架。
  • 當你理解原生 API 後,再學 jQuery、Axios、Alpine.js、Bootstrap 這類工具,會更清楚它們是在幫你省哪些重複工作;整體生態可接著看第 08 章;若要看經典 library 的實作寫法與範例,可再讀第 09 章;若要把 AJAX 的功能、流程與局部更新機制補完整,可再讀第 10 章。