DOM に変更が走るかどうか監視を行えるものにMutationObserver
API があります。使うにはまずインスタンスを作る必要があります。
const observer = new MutationObserver(callback);
引数にはcallback
が必要です。これは DOM に変更が走った時に発火するコールバック関数です。コールバック発火時この関数にはMutationRecord
というオブジェクトが配列渡ってきます。なぜ配列かというとそのタイミングで置きたすべての記録が渡される為です。MutationRecord
にはどういう変更が走ったのか(type
)やそれぞれのtype
で役立つ情報などが渡ってきます。
監視を始めるには作ったインスタンスobserver
のobserve
を対象の要素を引数に実行します。
observer.observe(node, {/* ... */});
監視を終えたい時はdisconnect
メソッドを実行します。これを実行すると今までにobserve
へ渡した要素についてすべて監視が解除されます。
observer.disconnect();
MutationObserverInit
MutationObserver#observe
する時、どういったものを監視するのかを指定する必要があります。このオプションで指定できる値は以下の7つです。
childList
subtree
attributes
attributeOldValue
attributeFilter
characterData
characterDataOldValue
この中で、attributes
とcharacterData
、childList
の内1つは必ずtrue
で設定しなければなりません。
ざっと見れば7つと分かりづらいですが、グループ分して以下の3つに分けて考えても良いと思います。
childList
と`subTreeattributes
とattributeOldValue
、attributeFilter
characterData
とcharacterDataOldValue
childList と subTree
要素が追加された、削除されたを監視したい場合はchildList
をtrue
で置きます。例えば自身がelement
だとして、element.appendChild
やelement.removeChild
などが呼ばれた時にコールバックが発火します。MutationRecord
へは要素が追加された場合はaddedNodes
に、削除された場合はremovedNodes
にそれぞれ対象の要素が渡されます。
上記のelement
ように監視対象が自分自身だけの場合ならこれでも良いですが、子が持つ要素も同じように監視したい場合にsubTree
をtrue
にします。これで何らかの手段である子要素に子要素ができた時にもコールバックを走らせれます。
observer.observe(item, {
childList: true,
subtree: true,
});
attributes と attributeOldValue、 attributeFilter
要素の属性が変わるかどうか監視したい場合はattributes
をtrue
で置きます。このtype
でコールバックが発火した時のみ、attributeName
に値が入ります。例えばstyle
属性を変更して発火したのであればstyle
のような感じです。
後の2つはオプショナルです。
attributeOldValue
をtrue
にすると、変更があった際のMutationRecord
のoldValue
に対象の属性の古い値が入ってきます。
attributeFilter
は属性を絞り込みたい場合に使います。例えば「value
属性は監視したいけど、id
属性の監視は要らないや」という場合以下のように設定します。
observer.observe(item, {
attributes: true,
attributeOldValue: true,
attributeFilter: ['id'],
});
characterData と characterDataOldValue
テキストが変わったかどうかを監視したい場合はcharacterData
をtrue
で置きます。characterDataOldValue
はオプショナルでtrue
にすると、attributeOldValue
のようにoldValue
プロパティに変更前のテキストが入ってきます、
observer.observe(node.childNodes[0], {
characterData: true,
characterDataOldValue: true,
});
このように監視した状態で以下のようにテキストを更新するとコールバックが発火します。
node.childNodes[0].nodeValue = 'update text';
実際に動いてる様子はCodeSandboxで見ることができます。