DOMの変更を検知するイベントが非推奨になり
代わりに新しく作られたMutationObserverなるもの。
MutationObserver - Web API インターフェイス | MDN
https://developer.mozilla.org/ja/docs/Web/API/MutationObserver
DOM変更検知は結構よく使うもの(特にユーザースクリプト)なのに
日本語の解説サイトが↑のMDNとMSDN、ここくらいしかなく
その都度ググったり手探りで片っ端から試すのが面倒なので以下に自分用にまとめる。
コンストラクタ
まずインスタンスを作る。
window.MutationObserverコンストラクタの引数に、DOM変更を検知した際に実行する関数を渡す。
function omega(data1, data2) { alert("ワレハメシアナリ"); console.log(data1); console.log(data2); } var mo = new MutationObserver(omega);
これで呼び出された関数には
第一引数に変更されたDOMの詳細が入った連想配列(MutationRecordsと呼ばれる)を含む配列が、
第二引数に呼び出し元のMutationObserverのインスタンスが入る。
メソッド
observe
インスタンスを作成しただけでは監視は行われない。
observeメソッドを実行して初めて監視が始まる。
var pikaman = document.getElementById("pikaman"), options = {childList: true}; var mo = new MutationObserver(omega); mo.observe(pikaman, options);
第一引数に監視対象のノード、第二引数に何をどこまで監視するかのオプションを書いた連想配列を入れる。
指定できるオプションは以下の通り。
基本オプション
名前 | 型 | 監視対象 |
---|---|---|
attributes | 真偽値 | 対象ノードの属性全般 (属性名/属性値は問わない) |
characterData | 真偽値 | 対象ノードの子となるテキストノード |
childList | 真偽値 | 対象ノードの子ノード |
どれもデフォルトでfalse。trueで有効化。
ここで言う監視とは、「新規/変更/削除」全てのアクションを指す。
上記の3つが基本にして、どれか1つ必須。
じゃないと下記の追加オプションは指定できない。
追加オプション
名前 | 型 | 必須 | 効果 |
---|---|---|---|
attributeFilter | 配列 | attributes | 監視する属性名を限定する |
attributeOldValue | 真偽値 | attributes | 記録するDOMデータに変更前の属性データを加える |
characterDataOldValue | 真偽値 | characterData | 記録するDOMデータに変更前のテキストノードを加える |
subtree | 真偽値 | childList | 対象ノードの子孫ノードも監視する |
- attributeFilter
監視する属性名を指定したものだけに絞る。
例えばaタグのhrefとtargetの変更だけキャプチャしたい場合は以下のようにする。
var attr = ["href", "target"], options = {attributes: true, attributeFilter: attr}; var mo = new MutationObserver(omega); mo.observe(pikaman, options);
- attributeOldValue
MutationRecordsのoldValueというプロパティに変更前の属性値を記録するようにする。
- characterDataOldValue
同上。属性値の代わりに変更前のテキストノードを記録。
- subtree
対象の子ノードだけでなく、子孫(その配下にある全ての子ノード)の変更もキャプるようにする。
これを使うにはchildList指定必須。
それを知らなかった私は{subtree: true}
とだけ書いたオプションを渡して
なんで動かないのかと軽く詰まった…。
MutationObserverで置き換えられるDOMイベント
DOMイベント | MutationObserverプロパティ (括弧内は任意) |
---|---|
DOMAttrModified | attributes: true (, attributeOldValue: true) (, attributeFilter: ["属性名"]) |
DOMAttributeNameChanged | attributes: true (, attributeOldValue: true) (, attributeFilter: ["属性名"]) |
DOMCharacterDataModified | characterData: true (, characterDataOldValue: true) |
DOMNodeInserted | childList: true (, subtree: true) |
DOMNodeInsertedIntoDocument | childList: true (, subtree: true) |
DOMNodeRemoved | childList: true (, subtree: true) |
DOMNodeRemovedFromDocument | childList: true (, subtree: true) |
DOMSubtreeModified | childList: true, subtree: true |
disconnect
observeで開始した監視を中止する。
var mo = new MutationObserver(omega); mo.observe(pikaman, options); mo.disconnect();
当然だが、監視するプロセスが増えれば増えるほど負荷がかかる。
監視する必要が無くなったらdisconnectして解放しよう。
takeRecords
それまでobserveで記録されたMutationRecordsの内容を全て配列として返す。
と同時に、それまでの記録をクリアする。
var mo = new MutationObserver(omega); mo.observe(pikaman, options); console.log( mo.takeRecords() );
MutationRecords
記録されるデータ一覧。
名前 | 型 | 戻り値 |
---|---|---|
attributeName | 文字列 | 変更された属性値が属する属性名 |
attributeNamespace | 文字列 | 変更された属性名の名前空間 |
addedNodes | ノードリスト | 追加されたノードの一覧 |
removedNodes | ノードリスト | 削除されたノードの一覧 |
previousSibling | ノード | 追加(削除)されたノードの直前にあるノード |
nextSibling | ノード | 追加(削除)されたノードの直後にあるノード |
target | ノード | 変更されたノード |
type | 文字列 | 基本オプションの内容(attributes、characterData、childList) |
oldValue | 文字列 | 上述の追加オプションで指定した内容 |
動作環境
で、問題のブラウザ対応状況だが
FirefoxとChromeはとっくの前に対応済み。
IEは11から。OperaはBlink版から。(Presto版非対応)
IE11のシェアが伸びてきたとは言え、まだまだIE10も多いのが現実。
フォールバックするのも面倒だし、jQueryの.on()で手軽に使えるという点でも
結局DOMイベントに甘えちゃうんだよねぇ。。