要素の属性値が変わったとき、要素が追加・削除されたとき、要素の中身が変更されたとき・・・
このような場合に変更を感知して何かイベント処理したいこともありますよね?
ただ標準のイベントではそれを感知する術はありません。
では諦めるしかないのか、というとそうではなく解決策はあります。
ここでは要素(DOM)の変化の監視方法について紹介します。
要素の変化の感知にchangeは使えない・・・
まず初めに注意しておきたいこと
それは要素の中身の変化、要素の追加や削除の感知にchangeイベントは使えないということです。
例えば次のようにjQueryでdiv要素の中身の変化を change で監視しようとしても無駄です。
1 2 3 4 5 |
$(function(){ $('div.example').on('change', function(){ /** div内のテキストが変更されたときの処理 */ }); }); |
上のようなコードは何もしていないのと同じです。
なぜならchangeイベントというのは入力欄のvalue属性の値が変化したときだけに発生するからです。
入力欄というのは例えばテキストエリアとかチェックボックスとか選択肢のこと
それに当てはまらないdiv要素などではそもそもchangeイベントは起こりません。
ではどうすれば要素の変化を監視できるのか・・・
その正しい答えは MutationObserver というJavaScriptのAPIを使うことです。
MutationObserverとは何か?その特長
MutationObserverは要素(DOM)の変化時に指定したコールバック関数を実行できるAPIです。
先ほど書いたようにこれはjQueryの機能ではなく、JavaScriptで用意されたAPIとなっています。
ではこのMutationObserverで要素の変化の何が監視できるかというと主に次のようなこと
- 属性値・CSSプロパティの変化
- 要素の追加・削除
- 要素内のテキストの変更
- その他色々・・・
つまり今まで監視できなかった要素の色々な変化をイベントとして受け取ることができるってことです。
MutationObserverの各ブラウザの対応状況については Can I use... の次のページから確認可能
Opera Mini以外はすべてのブラウザで対応済みなので実用的に使えます。
MutationObserverでDOM変化を監視する方法
ではこれを使って要素を監視する手順を大まかに書くと次のような感じ
- MutationObserverを作ってコールバック関数登録
- observeメソッドに監視したい要素とオプションを渡す
これだけだと分かりにくいの次で例を使って説明していきます。
まず次のようにMutationObserverインスタンスを作成
1 2 3 4 |
var observer = new MutationObserver(function(){ /** DOMの変化が起こった時の処理 */ console.log('DOMが変化しました'); }); |
インスタンスを作るときにコールバック関数が渡せ、DOM変化が起こった時にそれが実行されます。
今回はノード変化があるたびにコンソールにメッセージを出力してみます。
そうしたら次は変化を監視したい要素を getElementById で取得
1 |
const elem = document.getElementById('#my_example'); |
上の例のように 'my_example' などのIDを指定して要素オブジェクトを取得すればOKです。
では次にDOM監視時のオプションを作成しましょう。
1 2 3 4 5 |
const config = { attributes: true, childList: true, characterData: true }; |
この例のように連想配列形式で1つ以上のプロパティを持つオプションを作ってください。
オプション内で指定できる各プロパティとその意味についてはそれぞれ次の通り
プロパティ | 取れる値 | 意味 |
---|---|---|
childList | true または false | 子ノードの変化も監視するかどうか |
attributes | true または false | ノードの属性変化を監視するかどうか |
characterData | true または false | ノードのデータ変化を監視するかどうか |
subtree | true または false | 子孫ノードの変化も監視するかどうか |
attributeOldValue | true または false | 変更前のノードの属性値を記録するかどうか |
characterDataOldValue | true または false | 変更前のノードのデータを記録するかどうか |
attributeFilter | 属性ローカル名の配列 |
ノードの属性値やデータの変化を監視対象に含めるか、あるいは子ノードや子孫ノードも監視対象にするか、などの設定ができます。
では最後に先ほど作成したMutationObserverに対して次のようにobserveメソッドを実行しましょう。
1 |
observer.observe(elem, config); |
これで指定した要素またはその子・孫要素内で属性変化やデータ変化があるたびにコールバック関数が呼ばれることになります。
ちなみにここまでの全体のコードは次の通り
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var observer = new MutationObserver(function(){ /** DOMの変化が起こった時の処理 */ console.log('DOMが変化しました'); }); /** 監視対象の要素オブジェクト */ const elem = document.getElementById('#my_example'); /** 監視時のオプション */ const config = { attributes: true, childList: true, characterData: true }; /** 要素の変化監視をスタート */ observer.observe(elem, config); |
この例だと要素の属性変化(attributes)、子ノードの変化(childList)、要素内テキストの変化(characterData)の3つの変化を監視しています。
以上がMutationObserverの使い方です。
ほとんどのブラウザで対応済みなので特に互換性なども気にする必要もありません。
まとめ
MutationObserverを使うと簡単に要素の変化が監視できます。
jQueryが使えないのが少し残念ですが、使い方もそれほど難しくないので便利です。
ということで要素の変化を受け取るのにMutationObseverを使おうよという話でした。
ではではヾ(・◇・)ノ