📚

【JavaScript】Web APIインターフェースを使ってみた-其の1:MutaionObserver

2025/02/18に公開

このシリーズについて

初のシリーズ企画&JavaScript関連の記事です。
最近はJavaScriptでの機能改修・実装をする業務が多くなってきました。
そんな中で、特にWeb APIインターフェース群の活用が効率化・機能性の向上に大きく貢献していると感じ、どんなケースで使ったのかという具体例やコードも含めて、実際に使用したインターフェースについての有用性を簡単にまとめておきたいと思ったのがきっかけでした。

※MDNで多数のAPIとそのインターフェースが公開されています。
https://developer.mozilla.org/ja/docs/Web/API

では、シリーズ初のインターフェースを早速紹介していきましょう。

MutaionObserver

どんなことができるか

DOM(Webページの要素・コンテンツ)に変化があったかを監視できます。
特性上、非同期処理でコンテンツ追加があったかを監視するという重要な役割を担っているインターフェースだと思います。

使用した具体例

WordPressで、Googleカレンダーと手軽に連携したカレンダー設置ができるプラグイン【Simple Calendar】を導入するケースがありました。
https://ja.wordpress.org/plugins/google-calendar-events/
WordPress上で表示されたカレンダーの以下のイベントタイトル毎に、カレンダーのセルにCSSで着色したいという要望がありました。

  • 休日:赤
  • 半休という文字列が入っている:オレンジ
  • 担当者hogeの名前が入っている:青
  • 担当者hugaの名前が入っている:緑

ただ、このカレンダーは上部にある矢印で表示月を変更すると非同期処理で月カレンダーを更新するため、初期レンダリング後に加えて月が変更された非同期処理後もJavaScriptでクラス付与するという対応が必要になります。

そんな時は、MutationObserverを使えば負担なく解決できます。

コード例

ちょっと冗長な部分がありますが…半休は午前や午後のパターンにも対応できるようにincludesを利用しています。
simcal-calendarクラスを監視対象としています。

window.addEventListener('DOMContentLoaded', () => {
  const addClassToEvents = () => {
    const holiday = document.querySelectorAll('.simcal-event-title');
    
    holiday.forEach((day) => {
      if (day.textContent === '休日') {
        day.closest('.simcal-day').classList.add('calendar-holiday');
      } else if (day.textContent.includes('半休')) {
        day.closest('.simcal-event').classList.add('calendar-half-holiday');
      } else if (day.textContent.includes('hoge')) {
        day.closest('.simcal-event').classList.add('staff-1');
      } else if (day.textContent.includes('huga')) {
        day.closest('.simcal-event').classList.add('staff-2');
      }
    });
  };

  // 初期ロード時のクラス付与
  addClassToEvents();

  // 前月・次月ボタンを押したときにカレンダーが非同期に更新されたら再度クラス付与を実行する
  const calendarContainer = document.querySelector('.simcal-calendar'); // カレンダーが描画されているコンテナ要素
  
  const observer = new MutationObserver(() => {
    addClassToEvents();
  });

  // カレンダーのDOM変化を監視
  observer.observe(calendarContainer, {
    childList: true,  // 直下の子要素の変化を監視
    subtree: true     // 子孫要素の変化も監視
  });
});

このようなコードで解決ができました。

observeメソッドを深掘りする

さらに、コード例の最後にはobserveメソッドにオプションの引数を加えて、子要素や子孫要素も含めて変更を監視するようにしています。

observeメソッドはほかにもオプションでこんなことができます。

  • 属性の変更を監視
  • 監視する属性名を絞る(フィルター)
  • 監視属性やテキストの変更前の前回値を記録する

MDNのobserveメソッドをご覧頂くと、分かりやすいサンプルが掲載されています。
https://developer.mozilla.org/ja/docs/Web/API/MutationObserver/observe

使ってみて

MutationObserverを知らなかった時は「非同期処理後のコンテンツに対して、どのように変更処理対応すれば良いのだろう…」とモヤモヤした気持ちがあったのですが、初めて使った時には少し感動しました。
使いどころがかなり多いインターフェースだと感じたので、これからもどんどん活用したいものの一つです。

終わりに

最近、あまりZennの投稿ができていなかったのですが、シリーズ企画を通して発信頻度を高めたいなと思います。
他のテーマの記事投稿もしていきたいですね…
次回もお楽しみに!

Discussion