使用 MutationObserver 監聽 DOM 變化並更新 Cookie 的實作筆記

前言

在 Web 開發中,動態更新的 DOM 元素常因 AJAX 或前端框架渲染而改變,這些變化不一定會觸發傳統事件。若需要即時監控特定元素內容變化並同步更新到 Cookie,MutationObserver 是一個有效的解決方案。本文針對如何監聽 class 為 .am-cappa__name 的元素變化,並將其內容存入 Cookie 進行說明。

為何需要監聽 DOM 變化?

動態網頁中,元素內容可能透過非同步請求或前端框架更新,這些變化不會觸發像 click、input 等事件。若想在內容變更時執行特定邏輯(例如同步資料),MutationObserver 可監聽子節點或文字內容的變動,達成即時反應。

監聽 .am-cappa__name 並更新 Cookie 的核心邏輯

  1. 使用 MutationObserver 監聽目標元素的子節點與文字變化:
    const observer = new MutationObserver(() => {
    saveCappaName();
    });
  2. 透過 observer.observe() 設定監聽選項,包含 childListcharacterDatasubtree,確保所有子節點及文字變化都能被捕捉。
  3. 定義 saveCappaName() 函式,取得 .am-cappa__name 元素的文字內容,並與上一次儲存的值比較,若不同則更新 Cookie:
    function saveCappaName() {
    let cappaElement = document.querySelector(".am-cappa__name");
    if (cappaElement) {
     let cappaValue = cappaElement.innerText.trim();
     if (cappaValue && cappaValue !== lastCappaValue) {
       document.cookie = "am_cappa_name=" + encodeURIComponent(cappaValue) + "; path=/; max-age=86400";
       lastCappaValue = cappaValue;
     }
    }
    }
  4. 初始時嘗試取得目標元素並啟動監聽,若元素尚未載入,使用 setTimeout 每 500ms 重試,確保監聽能啟動。
  5. 為避免 MutationObserver 在某些情況下漏掉變化,額外使用 setInterval 每 500ms 強制執行一次 saveCappaName(),提高更新可靠性。

為何要存入 Cookie?

  • 跨頁面存取:Cookie 可在不同頁面間共享資料,方便維持狀態。
  • 持久化資料:設定 max-age=86400,資料可保存一天,使用者關閉瀏覽器後仍可讀取。
  • 後端存取:伺服器可從 HTTP 請求中讀取 Cookie,做進一步處理或驗證。

實際應用與延伸

此技術適用於動態表單內容的即時保存、使用者偏好設定同步等場景。未來可結合 LocalStorage 或 IndexedDB 進行更複雜的資料管理,或搭配前端框架的狀態管理提升效能。

常見坑

  • MutationObserver 監聽範圍設定不當可能漏掉變化,需包含 subtree
  • 監聽目標元素尚未載入時需重試,否則無法啟動監聽。
  • Cookie 大小限制與安全性考量,敏感資料不宜存放。

完整程式碼

document.addEventListener("DOMContentLoaded", function () {
  let lastCappaValue = ""; // 儲存上一次的值,避免重複存相同的值

  function saveCappaName() {
    let cappaElement = document.querySelector(".am-cappa__name");
    if (cappaElement) {
      let cappaValue = cappaElement.innerText.trim();
      if (cappaValue && cappaValue !== lastCappaValue) {
        document.cookie = "am_cappa_name=" + encodeURIComponent(cappaValue) + "; path=/; max-age=86400";
        console.log("Cookie 更新成功: " + cappaValue);
        lastCappaValue = cappaValue; // 更新最後的值
      }
    }
  }

  // 使用 MutationObserver 監聽 `.am-cappa__name` 是否變更
  const observer = new MutationObserver(() => {
    saveCappaName(); // 內容變更時,更新 Cookie
  });

  function startObserving() {
    let targetElement = document.querySelector(".am-cappa__name");
    if (targetElement) {
      observer.observe(targetElement, { childList: true, characterData: true, subtree: true });
      saveCappaName(); // 先存一次當前值
    } else {
      // 若元素還沒出現,每 500ms 檢查一次
      setTimeout(startObserving, 500);
    }
  }

  // 額外增加每 500ms 手動檢查一次
  setInterval(() => {
    saveCappaName();
  }, 500);

  startObserving(); // 啟動監聽
});