読者です 読者をやめる 読者になる 読者になる

はりをきば

そこにピカマンがいる限り 私はテイッハットウッをやめない


Caution!!
この日記はバカな私(はりを)が何かを忘れない為に、バカの一つ覚えの如く色んな記事を投稿しています。…が、
あくまでもただの備忘録のひと握りに過ぎず、情報の信憑性や真偽までは保証していません。
極力正しい情報をまとめているつもりですが、万一誤った記事の内容を実行しトラブル等が発生しても
当方は如何なる責任を負いません。自己責任でご利用ください。

以上に同意する方のみ、この雑記帳の閲覧をお願いします。

初めての方はこちらも併せてお読みください。このブログについて (About)


…ちゃ、ちゃんと予防線張ったからな!! ホント何があっても知らねーからな!!!(小学生並の言い訳)

予防線(☢Caution!!☢)の表示
テキスト全般の表示に使うフォント (大抵は「メイリオ」か「ヒラギノ角ゴ ProN W3」) (マルチバイト文字はSource Han Sansと同じ) (マルチバイト文字はNoto Sansと同じ)
ソースコードの表示に使うフォント
ピカマンロケットの効果音

設定を保存キャンセル

【JavaScript】 MutationObserverの使い方 個人的まとめ

JavaScript

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イベントに甘えちゃうんだよねぇ。。