iFrame src変更イベントの検出?


181

iframeのコンテンツを制御できない場合、親ページを介してsrcの変更を検出する方法はありますか?ある種のオンロードかもしれませんか?

私の最後の手段は、iframe srcが以前と同じである場合に1秒間隔のテストを行うことですが、このハッキーなソリューションを実行するのは面倒です。

役立つ場合は、jQueryライブラリを使用しています。


3
srciframe内のリンクをクリックすると、プロパティは変更されますか?私はそれについて確信がありません-もし私が推測しなければならなかったら、「いいえ」と言うなら。ありますプロパティを監視する方法は、(少なくとも私の知る限りではFirefoxで)私はそれが、この場合、任意の使用されるであろうかどうかはわかりません。
ペッカ

私はこのようなものを実装しようとしてsrcおり、DOM の属性がFireFoxまたはSafariの最新バージョンで変更されていないことを確認できます。以下の@Michielの回答は、私がこれまでに得ることができたのと同じくらい良いです。
Kaelin Colclasure 2014

回答:


201

onLoad次の例のように、イベントを使用することができます。

<iframe src="http://www.google.com/" onLoad="alert('Test');"></iframe>

アラートは、iframe内の場所が変更されるたびにポップアップします。最新のすべてのブラウザで動作しますが、IE5や初期のOperaなどの非常に古いブラウザでは動作しない場合があります。(出典

iframeが親の同じドメイン内のページを表示している場合、contentWindow.location次の例のように、を使用して場所にアクセスできます。

<iframe src="/test.html" onLoad="alert(this.contentWindow.location);"></iframe>

13
this.contentWindow.location.href
ニコライ

@Daniel Vassalloは、セキュリティの問題を処理したいときにこのアプローチを取ると想定して、誰かがonLoadイベントをオーバーライドしてからiframeコンテンツを変更できないのではないでしょうか。
Noam Shaish

15
私はときthis.contentWindow.location.href私が得るPermission denied to access property 'href'
Mazatec

4
this.contentWindow.location.hrefは、クロスオリジンリクエストを実行しているbcozでは機能しません。:(すべてのブラウザは今のことを制限する。
のNaveen

2
修正:this.contentWindow.location他のドメインで利用可能です。this.contentWindow.location.href他のドメインでも利用できますが、書き込みのみです。ただし、読み取りthis.contentWindow.location.hrefは同じドメインに限定されます。
ワディム2015年

57

JQuery <3に基づく回答

$('#iframeid').load(function(){
    alert('frame has (re)loaded');
});

subharbで述べたように、JQuery 3.0以降では、これを次のように変更する必要があります。

$('#iframe').on('load', function() {
    alert('frame has (re)loaded ');
});

https://jquery.com/upgrade-guide/3.0/#breaking-change-load-unload-and-error-removed


2
計画どおりに機能しない。最初のページの読み込み時にアラートを発生させます。このコードに対するあなたの計画に応じて(私にとっては、フォーム送信時にページ外のダイアログをアニメーション化しています)、このソリューションは機能しません。
2015年

@stracigh、正解です。フレームが読み込まれるたびにイベントが発生するため、最初のページの読み込みでもイベントが発生します。初めてコードをトリガーしたくない場合は、何とかしてこれが最初のフレームのロードとリターンであることを検出する必要があります。
ミシエル2015年

@FooBar、はい、クロスドメインで動作します。実際、それが私が使用したものです。ただし、そのページが別のドメインにある場合、JavaScriptを使用してiFrameのページにアクセスすることはできません。
Michiel、2015

これは機能し、コンテンツが読み込まれたことを検出します。srcが変化したことを検出する方法が必要です。beforeLoadのようなもの(ローダーをアクティブにするため)
Andrea_86

@stacighで示されているように、親ページの読み込み時にイベントを1回起動します。その関数の外部でカウンターを宣言して内部で読み取ると、その後の変更を検出できます。onloadハンドラーの内部でカウンターをインクリメントしますif (counter > 1) { // do something on iframe actual change }(開始時にカウンターが0に設定されていると想定)
Alex

38

ページを制御できず、何らかの変更を監視したい場合は、現代的な方法で MutationObserver

その使用例、src変更する属性を監視iframe

new MutationObserver(function(mutations) {
  mutations.some(function(mutation) {
    if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
      console.log(mutation);
      console.log('Old src: ', mutation.oldValue);
      console.log('New src: ', mutation.target.src);
      return true;
    }

    return false;
  });
}).observe(document.body, {
  attributes: true,
  attributeFilter: ['src'],
  attributeOldValue: true,
  characterData: false,
  characterDataOldValue: false,
  childList: false,
  subtree: true
});

setTimeout(function() {
  document.getElementsByTagName('iframe')[0].src = 'http://jsfiddle.net/';
}, 3000);
<iframe src="http://www.google.com"></iframe>

3秒後に出力

MutationRecord {oldValue: "http://www.google.com", attributeNamespace: null, attributeName: "src", nextSibling: null, previousSibling: null…}
Old src:  http://www.google.com
New src:  http://jsfiddle.net/ 

オンjsFiddle

元の質問がこの質問の複製としてクローズされたため、ここに回答を投稿しました。


Webコンポーネントを使用していて、カスタムコンポーネントの1つにsrc属性がある場合はどうなりますか?これは誤って拾ってしまうと思います。
ルーク、

次に、のオプションを変更しますobserve。これはほんの一例です。
Xotic750

@PaulRoubはjsfiddleリンクを削除し(コピー/貼り付けエラーでなければなりません)、コードをスニペットとして含めました。
Xotic750

4
しかし、私の場合、frame.contentDocument.URLはsrcではなく(フレーム内のリンクから)変更されます。観てもいいですか?
httpete

わかりません。質問を書くのが一番だと思います。
Xotic750 2016

11

注:スニペットは、iframeの原点が同じ場合にのみ機能します。

他の回答はloadイベントを提案しましたが、iframeの新しいページが読み込まれたに発生ます。新しいページが読み込まれた後ではなく、URLが変更された直後に通知が必要になる場合があります

これは単純なJavaScriptソリューションです。

function iframeURLChange(iframe, callback) {
    var unloadHandler = function () {
        // Timeout needed because the URL changes immediately after
        // the `unload` event is dispatched.
        setTimeout(function () {
            callback(iframe.contentWindow.location.href);
        }, 0);
    };

    function attachUnload() {
        // Remove the unloadHandler in case it was already attached.
        // Otherwise, the change will be dispatched twice.
        iframe.contentWindow.removeEventListener("unload", unloadHandler);
        iframe.contentWindow.addEventListener("unload", unloadHandler);
    }

    iframe.addEventListener("load", attachUnload);
    attachUnload();
}

iframeURLChange(document.getElementById("mainframe"), function (newURL) {
    console.log("URL changed:", newURL);
});
<iframe id="mainframe" src=""></iframe>

これsrcにより、属性の変更と、iframe自体から行われたURLの変更が正常に追跡されます。

すべての最新ブラウザでテスト済み。

私もこのコードで要点を作りました。私の他の答えもチェックできます。これがどのように機能するかについて少し詳しく説明します。


6

iframeは常に親ページを保持します。これを使用して、iframe内にいるページを検出する必要があります。

HTMLコード:

<iframe id="iframe" frameborder="0" scrolling="no" onload="resizeIframe(this)" width="100%" src="www.google.com"></iframe>

Js:

    function resizeIframe(obj) {
        alert(obj.contentWindow.location.pathname);
    }

2

Jqueryのバージョン3.0以降、エラーが発生する可能性があります

TypeError:url.indexOfは関数ではありません

これを行うことで簡単に修正できます

$('#iframe').on('load', function() {
    alert('frame has (re)loaded ');
});

1

Commerce SagePayCommerce Paypoint Drupalモジュールで使用されるメソッドは次のとおりです。document.location.href、最初に独自のiframeをロードし、次に外部のiframeをロードすることで古い値します。

したがって、基本的には、独自のJSコードと非表示のフォームを持つプレースホルダーとして空白のページをロードするという考えです。次に、親のJSコードは、その非表示フォームが#action外部iframeを指す場所に送信します。リダイレクト/送信が行われると、そのページでまだ実行されているJSコードは、document.location.href値の変更を。

iframeで使用されるJSの例を次に示します。

;(function($) {
  Drupal.behaviors.commercePayPointIFrame = {
    attach: function (context, settings) {
      if (top.location != location) {
        $('html').hide();
        top.location.href = document.location.href;
      }
    }
  }
})(jQuery);

そして、これが親ページで使用されているJSです:

;(function($) {
  /**
   * Automatically submit the hidden form that points to the iframe.
   */
  Drupal.behaviors.commercePayPoint = {
    attach: function (context, settings) {
      $('div.payment-redirect-form form', context).submit();
      $('div.payment-redirect-form #edit-submit', context).hide();
      $('div.payment-redirect-form .checkout-help', context).hide();
    }
  }
})(jQuery);

次に、一時的な空白のランディングページに、外部ページにリダイレクトするフォームを含める必要があります。


これはハックかもしれませんが、オーバーヘッドはミューテーションオブザーバーよりもかなり少ないです。シングルページアプリケーションで使用する場合は、このハッキングの残り物がガベージコレクションされるのを防ぐ参照を作成しないように注意してください。
ジェフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.