javascript MutationObserverを使ってDOMの監視を行う

javascript MutationObserverを使ってDOMの監視を行う

javascriptで、MutationObserverを使ってDOMの監視を行うサンプルコードを記述してます。

環境

  • OS windows11 pro 64bit
  • Apache 2.4.43
  • ブラウザ chrome 108.0.5359.72

MutationObserver使い方

MutationObserverを使用すると、DOMの監視を行うことが可能です。
実際に「MutationObserver」を使用してDOMに変化があった場合にコンソールにテキストを表示してみます。

<span id="txt" class="badge badge-primary">テキストデータ</span>

<script>

const target = document.getElementById('txt'); // ノードを指定

// ノードに変化があれば実行
const observer = new MutationObserver(function () {
  console.log("実行されました"); // 変化時の処理を記述
});

const config = { childList: true }; // 監視を指定するオプション

observer.observe(target, config); // 監視開始

// クリックしてテキストを変更
target.addEventListener("click", function() {
  target.textContent = "click";
});

</script>

実行結果をみると、監視対象の要素のテキストが変わると「MutationObserver」に指定した処理が実行されていることがわかります。

「config」に指定するオプションは以下となります。

オプション内容
childListtrue / false子ノード(テキストノードも含む)の変化を
監視する場合はtrue
attributestrue / false属性に対する変更を監視する場合はtrue
characterDatatrue / falseデータに対する変更を監視する場合はtrue
subtreetrue / false子孫ノードの変化を監視する場合はtrue

監視解除

監視を解除するには「disconnect()」を使用します。実際に解除してみます。

<span id="txt" class="badge badge-primary">テキストデータ</span>
<button id="btnStart">登録</button>
<button id="btnEnd">解除</button>

<script>

const target = document.getElementById('txt'); // ノードを指定

// ノードに変化があれば実行
const observer = new MutationObserver(function () {
  console.log("実行されました");
});

// 監視登録
document.getElementById('btnStart').addEventListener("click", function() {

  const config = { childList: true }; // 監視を指定するオプション

  observer.observe(target, config); // 監視開始

});

// クリックしてテキストを乱数に変更
target.addEventListener("click", function() {
  target.textContent = Math.random();
});

// 解除
document.getElementById('btnEnd').addEventListener("click", function() {
  observer.disconnect();
});

</script>

実行結果をみると、解除されていることが確認できます。

サンプルコード

以下は、
「テキスト変更」をクリックすると、指定した監視対象の要素のテキストを変更して、監視時に実行される処理をカウントする
サンプルコードとなります。

※cssには「bootstrap material」を使用してます。

<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="utf-8">
  <title>mebeeサンプル</title>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">
  <link rel="stylesheet"
    href="https://unpkg.com/bootstrap-material-design@4.1.1/dist/css/bootstrap-material-design.min.css"
    integrity="sha384-wXznGJNEXNG1NFsbm0ugrLFMQPWswR3lds2VeinahP8N0zJw9VWSopbjv2x7WCvX" crossorigin="anonymous">
</head>
<style>
  .main {
    margin: 0 auto;
    margin-top: 200px;
    display: flex;
    flex-direction: column;
    align-items: center;
    font-size: 25px;
    width: 500px;
  }
</style>
<script>

  let count = 0;

  function hoge() {

    // 監視対象の要素
    let obj = document.getElementsByClassName('badge');
    // テキストを変更
    if (obj[0].textContent === "b") {
      obj[0].textContent = "a";
    } else {
      obj[0].textContent = "b";
    }

  }

  window.onload = function () {
    // 監視対象の要素指定
    const target = document.getElementById('txt');
    // 変化があれば実行する処理
    const observer = new MutationObserver(function () {
      count++;
      document.getElementById('disp').textContent = `Mutationが実行されました${count}回目`;
    });
    // 要素のテキストノードの変更を監視
    const config = { childList: true };
    // 監視開始
    observer.observe(target, config);
  }

</script>

<body>
  <div class="main">

    <h2><span id="txt" class="badge badge-primary">テキストデータ</span></h2>
    <h2><span id="disp" class="badge badge-success">実行結果</span></h2>

    <button onclick="hoge()" type="button" class="btn btn-raised btn-secondary">
      テキスト変更
    </button>

  </div>

</body>

</html>

変更された回数だけ実行されているが確認できます。

また、javascript部は三項演算子を使い、windowオブジェクトやdocument.getElementByIdを省略して少し簡潔に記述することも可能です。関数もアロー関数を使用できます。

let count = 0;

const hoge = () => {
  // 監視対象の要素
  let obj = document.getElementsByClassName('badge');
  // テキストを変更
  (obj[0].textContent === "b") ? obj[0].textContent = "a" : obj[0].textContent = "b"    
}

onload = () => {    
  // 変化があれば実行する処理
  const observer = new MutationObserver( () => {
    count++;
    disp.textContent = `Mutationが実行されました${count}回目`;
  });
  // 要素のテキストノードの変更を監視
  const config = { childList: true };
  // 監視開始
  observer.observe(txt, config);
}