MutationObserver でiframe内を監視|DOMの変化を検知して処理を実行する方法
  1. 銀ねこアトリエ
  2. 海外ノマドブログ
  3. ウェブ制作
  4. JavaScript
  5. MutationObserver でif…

MutationObserver でiframe内を監視|DOMの変化を検知して処理を実行する方法

JavaScript の 要素の監視ができる Mutation Observer を使う機会があったので使い方をご紹介します。

この記事を書いた人

神守 由理子/フロントエンドエンジニア

資金ゼロからフィリピンで起業したアラフィフ海外ノマドエンジニア。最近は「フィリピンお役立ち情報」「ナチュラルアンチエイジング」「人生から得た哲学」など実体験を発信。最近AIの発達でテックブログはお休みしているけど、IT業界10年以上でテクニカルディレクター(技術責任者)・エンジニア講師・ブリッジSEを経てLenzTechnologies Inc.を設立し、代表を務める。

Mutation Observer とは?

MDN Web Docs によるとMutationObserver インターフェイスは、 DOM ツリーへ変更が加えられたことを監視できる機能
参照 : insertAdjacentElement MDN

Mutation とは突然変異の意味です。

今回は画面操作するたびに変更されるiframe内の高さを取得して、スクロールさせないようにしたかったのでその方法をそのまま記しておきます。

frameまたはiframe要素で読み込まれているページが別ドメインである場合、クロスドメインの制約に引っかかり取得できない場合があります。

iframe 内の必要な要素の値を取得する

ajaxなどで非同期で読み込んだコンテンツの表示が終わったら、iframeの高さを取得しiframeに直接スタイルを書き込みます。スクロールバーの表示されないので、埋め込み感がなくなります。

今回はiframe内で読み込まれるローディング画像の表示/非表示の変化を監視します。

HTML
<iframe src="index.html" frameborder="0" class="element"></iframe>
JavaScript
const iframe = document.querySelector(".element");

function setHeight() {
  iframe.height = `${iframe.contentDocument.documentElement.offsetHeight}px`
}
document.addEventListener('DOMContentLoaded', event => {
  iframe.onload = () => {
    //ローディング用の画像要素
    const app = iframe.contentDocument.querySelector('#app img')
    setHeight()
    const observer = new MutationObserver(function (mutations) {
      if (mutations[0].target.className === '') {
        setHeight()
      }
    });
    const options = {
      attributes: true,
      attributeOldValue: false,
      subtree: false
    }
    observer.observe(app, options)
  };
});

contentDocumentで要素の中身を取得します。

HTML の領域のサイズを得るためにdocumentElementオブジェクトを参照します。

iframe.height = `${iframe.contentDocument.documentElement.offsetHeight}px`
高さ詳細
offsetHeightボーダーやスクロールバーを含む高さ
scrollHeightマージン・スクロールバーを含まない内側の高さ
clientHeightボーダーやスクロールバーを含まない内側の高さ

observe(監視)に追加できるオプションです。

オプション説明
subtreetargetをルートとしたNodeのサブツリーをモニタリングするか
childListターゲットノードの子ノードの追加や削除を監視
attributesターゲットの属性の変化を監視。
attributeFilter監視する特定の属性名の配列。このプロパティが含まれていない場合、すべての属性の変更は変異通知を引き起こすデフォルトはfalse。
attributeOldValueターゲットの古い属性の値を記録
characterData文字の変更を監視。
characterDataOldValue古い文字のデータを記録。

observe(監視)以外のメソットです。

メソッド説明
disconnect()MutationObserver のインスタンスが今後の通知を受け取ることを、 observe() が再び呼び出されるまで停止します。
takeRecords()MutationObserver の通知キューから保留中の通知をすべて削除し、 MutationRecord の新しい配列 (Array) で返します。

参照 : MutationObserver MDN

おまけ・iframe内のデータ操作

iframe内の要素の操作方法の要素の削除方法のご紹介です。

iframe内の要素の削除

iframe.contentDocument.querySelector('header').remove()

iframe の head内に style 追加

iframeを親要素になじませるためにスタイルを追加することも可能です。

const styleTag = document.createElement('style')
styleTag.innerText = `
body {
  background: none;
}
`;
iframe.contentDocument.querySelector('head').insertAdjacentElement('beforeend', styleTag);

insertAdjacentElement の使い方です。呼び出された要素から相対的に指定された位置に、指定された要素ノードを追加できます。

メソッド説明
beforebeginターゲットの前
afterendターゲットの後
afterbeginターゲット内の最初の子要素の前
beforeendターゲット内の最後の子要素の後

insertAdjacentElement MDN

同じ要領で、他の要素も追加できます。

iframe内の要素のクラスの削除や追加

//追加
iframe.contentDocument.querySelector('main').classList.add('is-show')
//削除
iframe.contentDocument.querySelector('main').classList.remove('is-show')

まとめ・Mutation Observerを使えばイベント発火に関係なく監視したい要素の変化をキャッチできる

今回iframe内の要素の変化を監視して、iframeを操作する方法をご紹介しました。

Mutation Observer の他の使い方はまだやってませんが、可能性のあるAPIでした。

この記事がみなさんのコーディングライフの一助となれば幸いです。

最後までお読みいただきありがとうございました。

参照 : insertAdjacentElement MDN

関連記事もあわせてお読みください

Intersection Observer でQiita風目次|スクロール連動ハイライトの実装

読者が今どこを読んでいるか一目でわかる「Qiita風の動く目次」を、Intersection Observer APIを...

FAQ

MutationObserverを使うとパフォーマンスに悪影響はありますか?

監視対象(subtree)が広すぎると負荷がかかりますが、 特定の要素や属性に絞って監視 すれば、従来のインターバル(setInterval)による監視よりも圧倒的に効率的で低負荷です。

iframe内の要素がうまく取得できないのですが。

iframe内のコンテンツが 別ドメインの場合、ブラウザのセキュリティ制限(Same-Origin Policy) によりJavaScriptでの操作や監視はできません。自ドメイン内のコンテンツであることを確認してください。

監視を途中で止めることはできますか?

はい。インスタンスの disconnect() メソッドを呼び出すことで、いつでも監視を停止できます。メモリリークを防ぐためにも、不要になったタイミングで停止するのがベストプラクティスです。

どのような変化を具体的に検知できますか?

クラス名の付け替え、テキスト内容の変更、子要素の追加・削除など、DOMに関するあらゆる「変化」を検知可能です。optionsの設定によって監視範囲を細かく指定できます。

  1. Previous
  2. Next