トップへ(mam-mam.net/)

要素(DOM)のCSSや属性変更を監視 ~ MutationObserver

検索:

MutationObserverを使うと要素(DOM)のCSS等の属性変更を監視して、変更を検知したタイミングでコールバック関数を呼び出せます。
例えばヘッダーの高さがウィンドウの幅に応じて変化する場合に、メニューの位置をヘッダーの下端に合わせなければならない時などに重宝します。

実行サンプル

<div id="target_node">この要素がランダムに移動</div>
<div id="chase_node">この要素は上記要素を監視して変更を検知したら追従</div>

ソースコード

<div style="position:relative;width:100%;height:300px;">
  <div id="target_node" style="position:absolute;width:210px;height:80px;background:#DFF;">
    このノードがランダムに移動
  </div>
  <div id="chase_node"  style="position:absolute;width:210px;height:80px;background:#FFD;">
    この要素は上記要素を監視して変更を検知したら追従
  </div> 
</div>

<script>
  var tid;
  window.addEventListener("load",function(){
    
    //監視対象ノードに属性変更があった場合の処理
    const observer = new MutationObserver(function(MutationRecords){
      //変更内容は変数MutationRecordsに届く
      //console.log(MutationRecords);

      //#target_node に変更があるので #chase_node を追従させる
      let t = document.getElementById("target_node");
      let c = document.getElementById("chase_node");
      let r = t.getBoundingClientRect();
      c.style.left=(parseInt(t.style.left)+20)+'px';
      c.style.top=(parseInt(t.style.top)+r.height+10)+'px';
    });
    
    //#target_nodeの属性変更の監視を開始する
    observer.observe(
      document.getElementById("target_node"), //監視対象ノードを指定
      {
        childList: true, //対象ノードの子ノード(テキストノード含む)の変更も監視する場合はtrue
        attributes: true,        //対象ノードの属性変更を監視する場合はtrue
        characterData: true,     //対象ノードのデータの変更を監視する場合はtrue
        subtree: true,           //対象ノードの子孫ノードも監視対象に含める場合はtrue
        attributeOldValue: true, //変更前の属性値を記録(MutationRecords[].oldValue)する場合はtrue
        characterDataOldValue: false, //変更前のデータ(テキストノード)を記録(MutationRecords[].oldValue)する場合はtrue
        attributeFilter:['style'], //style属性(つまりCSS)の変更がないか監視
      }
    );

    //#target_nodeを2秒ごとにランダムな位置に移動させる
    tid=setInterval(function(){
        let elm=document.getElementById("target_node");
        let max=160;
        elm.style.left=Math.floor(Math.random() * max)+'px';
        elm.style.top=Math.floor(Math.random() * max)+'px';
      },
      2000);
  });

  window.addEventListener("unload",function(){
    //インターバルのクリア
    clearInterval(tid);
    //監視を中止
    observer.disconnect();
  });
</script>