もくじ
JavaScriptでWebページを動的に操作する際、DOM(ドキュメントオブジェクトモデル)の変化をリアルタイムに検知したい場面は多々あります。
たとえば、Ajax通信で新しい要素が追加された時や、特定のクラスや属性が動的に付与されたとき、その変化をトリガーに処理を実行したいこともあるでしょう。
従来はsetIntervalやイベントリスナーで無理やり監視していたケースもありますが、実は「Mutation Observer」を使えば、効率よく簡単にDOMの変化を監視できます。
本記事では、Mutation Observerの基本と実践的な使い方、コピペですぐ使えるサンプルコードまで、初心者にも分かりやすく解説します。
Mutation Observerのオプション一覧
- オプション
- 説明
- childList
- 対象ノードの子ノードの追加と削除を監視します。
値:trueまたはfalse
- attributes
- 対象ノードの属性の変更を監視します。
値:trueまたはfalse
- characterData
- 対象ノードのテキストの変更を監視します。
値:trueまたはfalse
- subtree
- 対象ノードおよびその子孫ノードの変化を監視します。
値:trueまたはfalse
- attributeFilter
- 特定の属性の変更のみを監視します。
値:監視する属性名の配列
- attributeOldValue
- 属性の変更前の値を記録します。
attributesがtrueの場合にのみ使用されます。
値:trueまたはfalse
- characterDataOldValue
- テキストの変更前の値を記録します。
characterDataがtrueの場合にのみ使用されます。
値:trueまたはfalse
必須オプションについて
MutationObserverを正しく動作させるためには、以下のいずれか1つのオプションを指定する必要があります。
childList
attributes
characterData
【実装・テンプレートコード】Mutation ObserverでDOMの変化を監視
以下のコードはテンプレートのため複数のオプションを設定していますが、実務で使用する場合は必要なオプションのみを設定して使用することが多いです。
// 監視対象の要素を取得const targetNode = document.querySelector('.watchElement');// オプション設定const config = { childList: true, attributes: true, characterData: true, subtree: true, attributeFilter: ['class', 'style', 'data-demo'], attributeOldValue: true, characterDataOldValue: true,};// 変更が発生したときに呼び出されるコールバック関数const callback = function(mutationsList, observer) { for (let mutation of mutationsList) { // 変更があった箇所(要素)を取得 let targetElement = mutation.target; if (mutation.type === 'childList') { // 子ノードに追加または削除があった場合の処理 console.log(`子ノードが追加または削除されました。変更箇所:`, targetElement); } else if (mutation.type === 'attributes') { // 属性に変更があった場合の処理 console.log(`${mutation.attributeName} 属性が変更されました。変更箇所:`, targetElement, `古い値: ${mutation.oldValue}`); } else if (mutation.type === 'characterData') { // テキストが変更された場合の処理 console.log(`テキストが変更されました。変更箇所:`, targetElement, `古い値: ${mutation.oldValue}`); } }};// MutationObserverのインスタンスを作成const observer = new MutationObserver(callback);// 監視対象の要素にMutationObserverを設定observer.observe(targetNode, config);【サンプル】Mutation ObserverでDOMの変化を監視
「クリック」ボタンを押下すると、上記実装コードで実装しているconsole.log()の内容をディベロッパツールのコンソールで確認できます。
サンプルで使用しているコード
<div class="watchElement">監視対象要素</div><button id="btn">クリック</button>// 監視対象の要素を取得const targetNode = document.querySelector('.watchElement');// オプション設定const config = { childList: true, attributes: true, characterData: true, subtree: true, attributeFilter: ['class', 'style', 'data-demo'], attributeOldValue: true, characterDataOldValue: true,};// 変更が発生したときに呼び出されるコールバック関数const callback = function(mutationsList, observer) { for (let mutation of mutationsList) { // 変更があった箇所(要素)を取得 let targetElement = mutation.target; if (mutation.type === 'childList') { // 子ノードに追加または削除があった場合の処理 console.log(`子ノードが追加または削除されました。変更箇所:`, targetElement); } else if (mutation.type === 'attributes') { // 属性に変更があった場合の処理 console.log(`${mutation.attributeName} 属性が変更されました。変更箇所:`, targetElement, `古い値: ${mutation.oldValue}`); } else if (mutation.type === 'characterData') { // テキストが変更された場合の処理 console.log(`テキストが変更されました。変更箇所:`, targetElement, `古い値: ${mutation.oldValue}`); } }};// MutationObserverのインスタンスを作成const observer = new MutationObserver(callback);// 監視対象の要素にMutationObserverを設定observer.observe(targetNode, config);const btn = document.getElementById('btn');btn.addEventListener('click', function () { // 要素の追加 let createElement = document.createElement('div'); createElement.textContent = '要素を追加'; targetNode.appendChild(createElement); // 属性の変更 targetNode.classList.add('demo'); targetNode.setAttribute('data-demo', 'demo'); // テキストの変更 targetNode.firstChild.data = '新しいテキスト';}, {once: true});【実装コード】子ノードの追加と削除を監視
// 監視対象の要素を取得const targetNode = document.querySelector('.watchElement');// オプション設定const config = { childList: true,};// 変更が発生したときに呼び出されるコールバック関数const callback = function(mutationsList, observer) { for (let mutation of mutationsList) { if (mutation.type === 'childList') { // 子ノードに追加または削除があった場合の処理 console.log('子ノードが追加または削除されました。'); } }};// MutationObserverのインスタンスを作成const observer = new MutationObserver(callback);// 監視対象の要素にMutationObserverを設定observer.observe(targetNode, config);【実装コード】属性の変更を監視
class等の属性の変更を監視することができます。
// 監視対象の要素を取得const targetNode = document.querySelector('.watchElement');// オプション設定const config = { attributes: true,};// 変更が発生したときに呼び出されるコールバック関数const callback = function(mutationsList, observer) { for (let mutation of mutationsList) { if (mutation.type === 'attributes') { // 属性に変更があった場合の処理 console.log('属性が変更されました。'); } }};// MutationObserverのインスタンスを作成const observer = new MutationObserver(callback);// 監視対象の要素にMutationObserverを設定observer.observe(targetNode, config);【実装コード】テキストの変更を監視
// 監視対象の要素を取得const targetNode = document.querySelector('.watchElement');// オプション設定const config = { characterData: true, subtree: true,};// 変更が発生したときに呼び出されるコールバック関数const callback = function(mutationsList, observer) { for (let mutation of mutationsList) { if (mutation.type === 'characterData') { // テキストが変更された場合の処理 console.log('テキストが変更されました。'); } }};// MutationObserverのインスタンスを作成const observer = new MutationObserver(callback);// 監視対象の要素にMutationObserverを設定observer.observe(targetNode, config);テキストの変更を監視する場合の注意点
対象ノードのテキストの変更をcharacterDataとして検知したい場合、オプションにsubtree: trueを指定します。
テキストの変更は、dataプロパティを使用してテキストノードを直接変更する必要があります。
例:targetNode.firstChild.data = '新しいテキスト';
textContent等でテキスト変更が行われている場合、characterDataで検知することはできません。
textContentでテキストが変更されている場合、childListを使用して監視する必要があります。
【実装コード】Mutation Observerの監視を停止する方法
disconnect()メソッドを呼び出すことで、Mutation Observerの監視を停止できます。
以下のコードは、子ノードに追加または削除があった場合に監視を停止します。
// 監視対象の要素を取得const targetNode = document.querySelector('.watchElement');// オプション設定const config = { childList: true,};// 変更が発生したときに呼び出されるコールバック関数const callback = function(mutationsList, observer) { for (let mutation of mutationsList) { if (mutation.type === 'childList') { // 子ノードに追加または削除があった場合の処理 console.log('子ノードが追加または削除されました。'); observer.disconnect(); // 監視を停止 break; // ループを抜ける } }};// MutationObserverのインスタンスを作成const observer = new MutationObserver(callback);// 監視対象の要素にMutationObserverを設定observer.observe(targetNode, config);まとめ
Mutation Observerを活用することで、JavaScriptでDOMの変化を効率良く監視し、動的なコンテンツやユーザー操作にも柔軟に対応できるようになります。
従来の方法よりも簡潔かつ高性能で、実務でも活用シーンが多いテクニックです。
本記事で紹介したサンプルコードや設定方法を活かして、ぜひご自身のプロジェクトに役立ててください。
「○○を検知したいけどどうすれば…」と感じたときは、Mutation Observerの利用を思い出しましょう!
