JavaScriptでDOMのCSSや属性変更を監視する方法|MutationObserverの使い方
初心者向けに、JavaScriptのMutationObserverを使ってDOMの属性やCSS変更をリアルタイム監視する方法を解説します!
例えば、ページ内の要素のレイアウトが変更された際に、それに合わせて別の要素を動的に調整することが可能です。
MutationObserverを使えば、ページのデザインを適応させる処理を効率的に行えます。
本記事では、コピペで使えるサンプルコード付きで、MutationObserverの基本的な使い方を詳しく説明します。
MutationObserverのメリットとは?
-
パフォーマンスが良い
setInterval() で定期的にDOMを監視する方法よりもMutationObserverは変更が発生した瞬間に処理が実行されるため、余計な計算を減らせます。 -
リアルタイム更新が可能
CSSが変更されたり、要素が追加・削除されたときに即座に反映できる。 -
細かい監視ができる
属性変更 (attributes)、子要素の追加・削除 (childList)、テキスト変更 (characterData) など、監視範囲を細かく指定可能。
MutationObserverの注意点と使い方
-
監視範囲を広げすぎないこと
subtree: true を使ってページ全体を監視すると不要な変更まで検出しパフォーマンスが低下する可能性があります。 -
変更前のデータを記録する場合は注意
attributeOldValue: true などを設定すると、変更前の値を記録できますが、監視対象が多すぎるとメモリ使用量が増えることに注意。 -
適切な解除処理 (disconnect()) を行う
ページ遷移時や不要になったときに observer.disconnect(); を呼び、不要な監視を避けることが重要。
実行サンプル
<div id="target_node">この要素がランダムに移動</div>
<div id="chase_node">この要素は上記要素を監視して変更を検知したら追従</div>
MutationObserverのコード例|コピペOK
<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(){ //MutationObserverの設定(#target_nodeの変更を監視) const observer = new MutationObserver(function(mutations){ //変更内容は変数mutationsに届く //console.log(mutations); //#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, //子ノードの追加・削除を監視(テキストノード含む) attributes: true, //要素の属性変更(style, id, class など)を監視 characterData: true, //テキストノードの変更も監視(文章が変更された場合など) subtree: true, //子孫ノードも監視対象に含める(階層構造全体を監視可能) attributeOldValue: true, //変更前の属性値を mutations[i].oldValue に記録(以前の値との比較が可能) characterDataOldValue: false, //変更前のテキストデータを mutations[i].oldValue に記録(文字列の比較をしたい場合に有効)しない attributeFilter:['style'], //監視対象を "style" 属性(つまりCSS)だけに限定 } ); //2秒ごとに#target_nodeの位置をランダム変更 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("beforeunload",function(){ //インターバルのクリア clearInterval(tid); //監視を中止 observer.disconnect(); }); </script>
