見出し画像

【JavaScript】こっちのjsで行った値変更をあっちのjsで感知したい-MutationObserverを使ってみる

表題の通りです。

地獄のスパゲッティと化してきたjsファイルを分割するにあたって、今までワンストップでやっていた処理を、「こっちは表示を変えるだけ」「表示が変わったらこっちで計算をし直す」に分割したいのですが、イベントリスナーのchangeだと、jsから行った値の変更は感知出来ない。

ということで調べてみたところ、MutationObserverが良さそうということで使ってみます。

結論

html

<html>
   <head>
       <script defer src="js/set.js"></script>
       <script defer src="js/update.js"></script>
   </head>
   <body>
       <div>定数+入力した数字を計算します</div>
       <div id="const">20</div>
       <input type="number" value="10" id="input">
       <div id="result">result</div>
   </body>
</html>

js1(画面の値を変更するjs)


let CONST_NUM = Number(document.getElementById("const").innerHTML);
let INPUT_OBJECT = document.getElementById("input");
let RESULT_OBJECT = document.getElementById("result");

function inputCheck(){
   INPUT_OBJECT.addEventListener("change", submit)
}

function submit(){
   let input_value = Number(document.getElementById("input").value)
   let result = input_value + CONST_NUM
   RESULT_OBJECT.innerHTML = "result=" + result;
}

window.addEventListener("DOMContentLoaded", inputCheck)

(このサンプルの内容なら、htmlの方にボタン足してonclick="submit()"しときゃ良いんですが、本番ではイベントリスナーで取得したい都合があるのでイベントリスナーを設定する様にしています。また、匿名関数だいきらい教の人間なので一々関数を定義しています)

js2(変更を感知して発火するjs)

function checker(event){
   console.log("change!!")
   console.log(event)
}

let observer = new MutationObserver(checker);
observer.observe(RESULT_OBJECT,{childList:true})

MutationObserverの使い方

0:変更を感知したときに実行させたい関数を作る
1:new MutationObserver()してインスタンスを作る
2:インスタンスを作るときに、第一引数として0で作った関数を渡す
3:observer.observe(RESULT_OBJECT,{childList:true})で、監視したいオブジェクトと、1つ以上のオプションをセットする

一つずつ見ていきます。

0:変更を感知したときに実行させたい関数を作る

引数としてeventを持つ関数を作ります。このeventの中には、変更内容についての情報が入ってきます。

   console.log(event[0])
   console.log(event[0].target)
   console.log(event[0].target.id)
   console.log(event[0].target.innerHTML)

みたいな感じで色々取れます。[0]してるのは、event自体は長さ2の配列で渡ってくるからです。0番目だけあればとりあえず十分。

詳細な中身は、console.log(event)してコンソール見てみてください。

1:new MutationObserver()してインスタンスを作る
2:インスタンスを作るときに、第一引数として0で作った関数を渡す

let observer = new MutationObserver(checker);

そのまんまです。コールバックとして渡すので、引数に渡す時には()は不要です。

3:observer.observe(RESULT_OBJECT,{childList:true})で、監視したいオブジェクトと、1つ以上のオプションをセットする

observer.observe(RESULT_OBJECT,{childList:true})

RESILT_OBJECTは、上のサンプルで

let RESULT_OBJECT = document.getElementById("result");

してたやつです。何らかのgetElementした結果を渡せばOK。

オプションについて

良く使いそうなものは以下の感じ。

childList / 子ノードの変化も監視するか
subtree / 子孫ノードの変化も監視するか
characterData / ノードの文字列部分の変化を監視するか
characterDataOldValue / 文字列部分の、変化前の情報を記録するか
attributes / ノードの属性変化を監視するかどうか
{childList:true, subtree:false, characterData:true}

みたいにオブジェクト(連想配列もどき)作って渡せばOKです。

そのほかの項目についても

ここにまとまっていますが、英語なので

https://pisuke-code.com/mutation-observer-usage/

こちらに日本語の見やすい表がありました。お好きな方で。

あとはこれで、コンソールを開きながら画面上の数値を変更してみると、変更が検知されているのが分かるはずです。やったね。

この記事が気に入ったらサポートをしてみませんか?