こんにちは、さち です。
先日、JavaScript を書いていたんですが、要素 <div> の中身が変化した時にイベントを起こしたいことがありました。
最初は、addEventListener の change を使ったんですがダメでした。要素の中身の変化を検出するには、MutasionObserver を使わないといけないみたいです。
「change」イベントでは動かない
<div> の中身が変更されたらアラート(ダイアログ)を出すように、<div> に addEventListener の change を設定して、こんな HTML, JavaScript を書きました。
<div>にー</div> <button>「にっこ」追加</button>
var div = document.getElementsByTagName('div')[0];
div.addEventListener('change', function() {
alert('divの中身が変更されたよ');
}, false);
var button = document.getElementsByTagName('button')[0];
button.addEventListener('click', function() {
div.textContent = 'にっこ' + div.textContent;
}, false);
しかし、下記のサンプルのとおりアラートは出ません。
addEventListener の change は、基本的に <input> や <select> の変化しか検出しないので、<div> の中身が変化しても何も起こらないのです。
「MutationObserver」を使う
MutationObserver を使うことで、<div> などの要素の中身の変更も検出できます。
Mutation(ミューテーション) は「変化」、Observer(オブザーバー)は「監視者」という意味なので、まさにそのままの名前です。
今回の例で使うとこんな感じ。
var div = document.getElementsByTagName('div')[0];
var mo = new MutationObserver(function() {
alert('divの中身が変更されたよ');
});
var config = {
childList: true
};
mo.observe(div, config);
var button = document.getElementsByTagName('button')[0];
button.addEventListener('click', function() {
div.textContent = 'にっこ' + div.textContent;
}, false);
実際のサンプルがこちら。ちゃんとアラートが出ます。
「MutationObserver」の使い方
MutationObserver を使う際の流れはこんな感じ。
//監視する要素の指定
var element = document.getElementById('id');
//MutationObserver(インスタンス)の作成
var mo = new MutationObserver(function(record, observer) {
/* 変更検出時に実行する内容 */
});
//監視する「もの」の指定(必ず1つ以上trueにする)
var config = {
childList: true,//「子ノード(テキストノードも含む)」の変化
attributes: true,//「属性」の変化
characterData: true,//「テキストノード」の変化
};
//監視の開始
mo.observe(element, config);
//監視の終了
mo.disconnect();
MutationObserver はインスタンスを作っただけでは機能しません。observe メソッドで監視を開始しましょう。
監視するものは、次の3つの中から必ず1つ以上有効(true)にします。
| childList | 子ノード(中身)の変化を検出 |
| attributes | 属性名,属性値の変化を検出 |
| characterData | テキストノードの変化を検出(「childList」が動かない時に有効にする認識でOK) |
監視する「もの」の指定では、下記の項目も併用できます。attributeOldValue characterDataOldValue を有効にした場合、変更前の値は MutationObserver の引数 record に配列として記録されます。
var config = {
childList: true,
attributes: true,
characterData: true,
subtree: true,//孫以降のノードの変化も検出
attributeOldValue: true,//変化前の属性データを記録する
characterDataOldValue: true,//変化前のテキストノードを記録する
attributeFilter: [],//配列で記述した属性だけを見張る
};
subtree: true は使う機会が多そうなので実験してみます。
どちらの <div> にも MutationObserver を設定し、childList: true としていますが、subtree の設定が異なっています。<div> 内にある <span> の中身を変える場合、subtree: true でないと反応しません。
ウェブブラウザーの対応
Can I use... によると、MutationObserver に対応している各ウェブブラウザーのバージョンは次のとおりです。
| Chrome | 18 以降 |
| Firefox | 14 以降 |
| Edge | すべて |
| Internet Explorer | 11 以降 |
| Safari | 6 以降 |
| iOS | 6.1 以降 |
| Android | 4.4 以降 |
よほど古いブラウザでない限りほぼ大丈夫ですね。


コメント