本文 AI 產出,尚未審核

JavaScript – DOM 與瀏覽器 API

主題:新增 / 移除元素


簡介

在前端開發中,DOM(Document Object Model) 是連結 HTML、CSS 與 JavaScript 的橋樑。透過 DOM,我們可以在執行時動態地建立、修改或刪除頁面元素,讓網站具備即時互動的能力。
無論是加入商品卡片、顯示錯誤訊息,或是依使用者操作即時移除不需要的區塊,都離不開「新增」與「移除」元素的技巧。掌握這些基本操作,不僅能提升開發效率,也能讓程式碼更具可讀性與可維護性。

本篇文章將從 概念說明、實作範例、常見陷阱、最佳實踐 以及 實務應用 四個面向,完整講解在瀏覽器環境下如何安全、有效地新增與移除 DOM 元素。適合剛踏入前端的初學者,也能為已有基礎的開發者提供中級層次的最佳實作參考。


核心概念

1. 何謂「節點」與「元素」

在 DOM 中,節點(Node) 是所有可被操作的基本單位,包含元素節點(Element)、文字節點(Text)與註解節點(Comment)等。本文主要聚焦於 元素節點,即 HTML 標籤所代表的物件,如 <div>、<li>、<button> 等。

2. 常用的新增方法

方法 說明 典型使用情境
appendChild() 把子節點加入到父節點的最後面 動態加入列表項目
insertBefore() 把子節點插入到參考節點之前 在特定位置插入廣告
append() / prepend()(HTML5) 可同時插入文字、HTML 字串或 Node,支援多個參數 快速插入多筆內容
replaceChild() 用新節點取代舊節點 替換舊的載入動畫

Tip:append() 與 prepend() 會自動將字串轉成 TextNode,若要插入 HTML,請使用 insertAdjacentHTML() 或 innerHTML。

3. 常用的移除方法

方法 說明 典型使用情境
removeChild() 從父節點移除指定子節點,並回傳被移除的節點 移除已完成的任務項目
element.remove()(HTML5) 直接在目標元素上呼叫,無需知道父節點 簡化程式碼的寫法
replaceWith()(HTML5) 用新節點取代當前元素,同時移除舊元素 取代舊的按鈕樣式

注意:removeChild() 會拋出 NotFoundError,若要安全移除請先檢查子節點是否真的存在於父節點之中。

4. 建立新元素的步驟

  1. 建立節點:document.createElement(tagName)
  2. 設定屬性與內容:element.setAttribute()、element.classList、element.textContent、element.innerHTML
  3. 插入 DOM:使用上表的新增方法之一

程式碼範例

以下示範 5 個常見且實用的 新增 / 移除 範例,均附有詳細註解。

範例 1:使用 appendChild() 動態加入清單項目

// 取得 <ul id="todo-list">
const ul = document.getElementById('todo-list');

// 建立 <li> 元素
const li = document.createElement('li');
li.textContent = '購買咖啡豆';

// 加入到 <ul> 最後
ul.appendChild(li);

說明:appendChild 會把新建立的 <li> 加到父節點的 最後,適合「堆疊」式的清單。


範例 2:使用 insertBefore() 在特定位置插入廣告

const container = document.querySelector('.article-content');
const ad = document.createElement('div');
ad.className = 'ad-banner';
ad.innerHTML = '<a href="https://example.com">點我看優惠</a>';

// 取得要插入前的參考節點(例如第一段落)
const referenceNode = container.querySelector('p');

// 若參考節點不存在,fallback 為末端
container.insertBefore(ad, referenceNode || null);

說明:insertBefore 需要兩個參數——新節點與參考節點。若參考節點為 null,等同於 appendChild。


範例 3:使用 append() 同時加入多筆內容(文字 + HTML)

const msgBox = document.querySelector('#message-box');

// 同時加入文字、HTML 以及另一個 Node
msgBox.append(
  '系統訊息:',
  document.createElement('br'),          // 換行
  '<strong>已完成</strong>',           // 會自動轉為 TextNode,若想保留 HTML 用 insertAdjacentHTML
  document.createElement('hr')
);

重點:append 允許傳入 任意數量 的參數,非常適合一次性寫入多筆資料。若傳入字串,會被視為 文字節點,不會被解析成 HTML。


範例 4:使用 element.remove() 移除指定卡片(HTML5)

// 假設每張卡片都有 .card class 且包含 .close 按鈕
document.addEventListener('click', function (e) {
  if (e.target.matches('.card .close')) {
    // 找到最近的 .card 父層
    const card = e.target.closest('.card');
    // 直接呼叫 remove()
    card.remove();
  }
});

說明:使用事件委派(event delegation)可以一次監聽所有 .close 按鈕,省去為每張卡片綁定個別監聽器。


範例 5:使用 replaceWith() 取代舊的載入動畫

const spinner = document.querySelector('#loading-spinner');

// 載入完成後,用內容取代 spinner
const content = document.createElement('div');
content.id = 'main-content';
content.innerHTML = '<h1>歡迎使用本網站</h1>';

spinner.replaceWith(content);

技巧:replaceWith 同時完成 移除 與 插入,讓程式碼更簡潔。


常見陷阱與最佳實踐

陷阱 可能的結果 解決方案
直接使用 innerHTML 產生大量元素 會導致 重排 (reflow) 與 重繪 (repaint),效能下降 使用 DocumentFragment 或 批次 append,一次寫入多筆節點
忘記移除事件監聽器 記憶體泄漏、意外觸發舊事件 在 removeChild 或 element.remove() 前,先呼叫 removeEventListener,或使用 事件委派
在迴圈中一次一次 appendChild 每次插入都會觸發 DOM 更新,效能不佳 建立 DocumentFragment,把所有子節點先加入 fragment,最後一次性插入
使用 appendChild 插入已存在於 DOM 的節點 會把節點從原位置搬移,可能造成 UI 突變 確認節點是否已在目標容器,必要時先 cloneNode(true)
對 null 呼叫 removeChild 產生 TypeError 先檢查 parentNode && childNode 再執行

最佳實踐

  1. 批次操作:使用 DocumentFragment 或 append(...nodes) 來減少重排。
  2. 保持語意:插入元素時,選擇最符合語意的 HTML 標籤(如 <ul>/<li>、<section>),有助於 SEO 與可讀性。
  3. 使用 classList 管理樣式:避免直接寫入 className,以免覆蓋既有類別。
  4. 避免過度依賴 innerHTML:若僅需插入文字,使用 textContent;若需要插入大量 HTML,先建立元素再插入。
  5. 清理資源:在元素被移除前,手動解除與之相關的 計時器、WebSocket、Observer 等,確保不留下隱藏的資源。

實際應用場景

場景 需求 建議的實作方式
動態表單 使用者點擊「新增欄位」產生更多輸入框 使用 createElement('input') + appendChild(),同時為每個欄位綁定 input 事件。
無限捲動 (Infinite Scroll) 捲動到底部時自動載入新文章 依照 API 回傳的資料,用 DocumentFragment 批次建立 <article>,最後一次 appendChild(fragment)。
即時聊天 收到新訊息即時顯示在聊天視窗 append() 新的訊息 <div>,並在插入後呼叫 scrollIntoView(),確保畫面自動滾動。
可關閉的通知條 點擊「X」即移除通知 透過事件委派監聽 .close,使用 element.remove() 移除整個通知容器。
圖片懶載入 (Lazy Load) 當圖片進入視窗時才載入 觀察者 (IntersectionObserver) 觸發時,用 setAttribute('src', ...),若需要替換佔位圖則使用 replaceWith()。

總結

在前端開發裡,新增與移除 DOM 元素 是最常見也最基礎的操作。透過本文的概念說明、五個實作範例、常見陷阱與最佳實踐,我們可以:

  • 快速建立、安全插入、有效移除 任意元素;
  • 避免效能瓶頸(如重排、記憶體泄漏);
  • 在真實專案(表單、無限捲動、即時聊天等)中靈活運用。

只要遵循 語意化、批次處理、資源清理 的原則,便能寫出乾淨、可維護且效能優秀的前端程式碼。祝你在 JavaScript 的 DOM 操作之路上,玩得開心、寫得順手!