自主的20%るぅる

各々が自主的に好き勝手書くゆるふわ会社ブログ

MutationObserver … JavaScript から DOM を監視する新しい方法

JavaScript でページ上の動きを拾うには…?

こんにちは、江嵜です。

みなさん、JavaScript 書いてますよね!

大体 Web アプリ作ってるときに JavaScript 書くとなると、やりたいことって
「テキストボックスに文字を入力されたときにー」とか、
「ボタン押されたときにー」とかだと思うんですけど、
そういった動きはどうやって JavaScript で検知していますか?

そうですね、 on とか addEventListener とか、
動作時に発生するイベントを監視して、そのイベントが発生したときに
何かしらの動作をさせる…というのが普通のやり方かと思います。

例えば、サンプルなんかでよくある「ボタンを押したときにログを出力する」とかだと

const hoge = getElementById('hoge');
hoge.addEventListener('click', function () {
  console.log('ボタンが押された!');
});

みたいなやりかたが普通、ですね。

この辺でカンの良い方はなんとなく、今日の話題が分かってきますね。
そうです。今回はその、普通の方法ではないやり方で、ページ上の動きを検知していきます。

MutationObserver というものが最近追加されました!

イベントでなければどうやるの…?というところで、今回はこちら。
「MutationObserver」を使っていきます。

とりあえず JavaScript で初めて出会ったものは、 MDN でしらべてみましょう。
https://developer.mozilla.org/ja/docs/Web/API/MutationObserver

MutationObserver とは、指定したコールバック関数を DOM の変更時に実行させる API です。

つまり、イメージ的には、これまでイベントを使っていた時は
「文字が入力された!」「ボタンが押された!」という事柄が発生した時に指定した動作をさせていましたが、
このイベントとして「DOM が更新された!」ということをきっかけに指定した動作を実行させることができるということですね。

…ちょっと言葉で説明するの難しいんで、とりあえず例題言ってみましょう。

実践

さて、ササっとコード書いてみます。

今回はこんな感じでー…

HTML

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <button id="btn">click me</button>
  <div id="target">
  </div>
</body>
</html>

JS

const target = document.getElementById('target');

// MutationObserver 作成
const observer = new MutationObserver(function () {
  console.log(target.children.length);
});

const config = { attributes: true, childList: true, characterData: true };

// 監視実行
observer.observe(target, config);


// ボタンを押したら target 要素内に div を追加する
const btn = document.getElementById('btn');

btn.addEventListener('click', function (e) {
  e.preventDefault();
  const div = document.createElement('div');
  div.textContent = "added."
  target.appendChild(div);
})

ボタンを押したら target ID の要素内に
div が一つ追加される、という内容ですね。

今回のポイントは前半部分。

const observer = new MutationObserver(function () {
  console.log(target.children.length);
});

ここでは MutationObserver を作成して、
変更が起こった際に何をするかを関数で渡してあげていますね。

今回は target 要素内の要素数をコンソールに出力させてみています。

ここでは MutationObserver を作成しても、
まだ実際にどの要素を監視するべきか、ということについては指定していないことに注意。

observer.observe(target, config);

で、こちらですね。
作成した MutationObserver に対して、 observe を実行していますね。
この時、第一引数の方に監視対象となる要素を、
第二引数の方にはオプションを渡してあげます。

実際にこれを実行してみると…
( 今回は https://jsbin.com/ で実行してみています)

確かに、ボタンを押して要素が追加されると同時に、
コンソールの方には 1,2,3 … と数字が出力されていますね!

いいカンジです!

MutationObserver に指定できるオプションは
https://developer.mozilla.org/ja/docs/Web/API/MutationObserver#MutationObserverInit
こちらを見てもらったら分かりやすいかと思います。

要は対象の DOM の子供も監視するかとか、 DOM の属性も監視するかとか、そういった設定ができるようになっています。

MutationObserver の使いどころ

ということで、DOM が更新されたことを検知できる MutationObserver を紹介いたしました。

が、もしかしたらこう思われている方もいらっしゃるかもしれないですね。

「DOM の更新を検知できて何がうれしいの?今回のサンプルだって、結局ボタンがクリックされたときのイベントを使うのと変わらなくない?」

確かにそうですね。
普通にプログラム書いていて、 MutationObserver 使いたい!って思うようなことはまずないかと思います。

ではいつ使うのか…それは…
Browser extension の作成時ですね!

いわゆる、ブラウザの「拡張機能」と呼ばれているヤツです。

Google Chrome ならこんな感じで、右上に小さいアイコンが並ぶ、
ブラウザの機能を拡張してくれるヤツです。

彼らは現在開いているページに対して、便利なボタンを追加してくれたり、
情報を収集してくれたりと便利な機能を提供してくれています。

が、しかし、彼らは言ってしまえば「勝手に」ページに介入しているものですから、詳細な画面の設計などは入手できませんし、それに、様々なページに対応する必要があります。
動的に画面が変わるページでは、イベントを使って正しく変化に追従するのは少し難しいところがあるのですね。

ということで、この MutationObserver を使えば、確実に画面の変換に対応ができる、という事で、とても便利に使うことができるのです!

皆さんも、使ってみると結構便利な MutationObserver 、使ってみてくださいね!

Let’s share this article!

{ 関連記事 }

{ この記事を書いた人 }

アバター画像
takato_ezaki
記事一覧