MutationObserverを使ってhidden属性の変更を監視する

image.png (59.9 kB)

TOC

やりたいこと

inputタグのtype属性で、type="hidden"の要素に対し、要素の変更を検知して任意のメソッドを発火したい

課題

通常のinput要素であれば、値が書き換わったときなどは、イベントリスナーのchangeイベントを設定して検知するなどの方法があると思いますが、type="hidden"のinput要素には残念ながらchangeイベントが発火しませんでした。

解決策

changeイベントで検知できないのであれば別の方法はないかと探していたところ、MutationObserverという、DOMツリーへ変更が加えられたことを監視するWebAPIがあったのでこちらを利用したところ、type="hidden"属性のinput変更でも変更を検知することができました。

MutationObserver

では、実際にどのように利用するかですが、まず初めに、MutationObserverのインスタンスを作製します。 引数にはコールバック関数を受け取ります。 このコールバック関数は、条件を満たすDOMの変更が発生する度に実行される関数です。

const observer = new MutationObserver(callback)

function callback(mutationList) {
  mutationList.forEach((mutation) => {
    // 条件によって実行したい処理を記述
  })
}

observerをインスタンス化し、対象の要素とオプションを指定し、observe()を呼び出す事で対象の要素の監視を開始します。

// 変更を監視したい要素
const target = document.querySelector('.target')

// オプションの指定
const config = {
  childList: true,
  attributes: true,
  subtree: true
}

observer.observe(target, config);

オプションはどの種類の変更に対応するかを指定を行うのに利用します。 (attributes/characterData/childListに関してはいずれか必須)

  • subtree:Boolean 監視する要素のすべての子孫に対する変更
  • childList:Boolean 監視する要素の子要素の追加・削除を監視
  • attributes:Boolean 監視する要素の属性に対する変更
  • attributeFilter:Array 監視する属性名を指定
  • attributeOldValue:Boolean 監視する要素の前の属性の値を記録
  • characterData:Boolean 監視する要素の文字データの変更を監視
  • characterDataOldValue::Boolean 監視する要素の文字データの以前の値を記録

監視を停止する場合は、disconnect()を呼び出します。

observer.disconnect()

使ってみる

これらを踏まえて、実際にMutationObserverを利用してみます。 今回は対象のinput要素のvalueが変更されたか検知する場合を想定して記述してみます。

const target = document.getElementById('target')
const config = {
  attributes: true,
  attributeFilter: ['value'],
}
const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.type === 'attributes') {
      console.log(`${mutation.attributeName}が変更されました!`)
      // 変更を一度検知したら監視を停止
      observer.disconnect()
    }
  })
})
// 要素の監視
observer.observe(target, config)

まとめ

なかなか使う機会は限られてくるかなとは思いますが、変更前のDOMの状態も取得出来たりと、イベントリスナーではできない機能もMutationObserverにはあったりするので、要件に対して適切に使い分けれるようになりたいなと思いました。

CONTACT
© 2023, Kakkiii All Rights Reserved.