IFRAMEの読み込みが完了したときのJavaScriptコールバック?


147

IFRAMEの読み込みが完了したら、コールバックを実行する必要があります。IFRAMEのコンテンツを制御できないため、そこからコールバックを起動できません。

このIFRAMEはプログラムで作成され、そのデータを変数としてコールバックで渡し、iframeを破棄する必要があります。

何か案は?

編集:

これが私が今持っているものです:

function xssRequest(url, callback)
{
    var iFrameObj = document.createElement('IFRAME');
    iFrameObj.src = url;            
    document.body.appendChild(iFrameObj);   

    $(iFrameObj).load(function() 
    {
        document.body.removeChild(iFrameObj);
        callback(iFrameObj.innerHTML);
    });
}

これはiFrameが読み込まれる前にコールバックするため、コールバックにはデータが返されません。


1
イベントハンドラーをiframe自体にアタッチするのではなく、コンテンツウィンドウです。
bobwienholt 2008年

1
問題はクロスドメインリクエストです。iframeが別のドメインからのものである場合は実行できません
ビクター

実際、iframeオブジェクトには、iframeがドキュメントの読み込みを完了するたびに起動するloadイベントがあります。そうでない場合は、読み込みのたびにウィンドウに接続する必要があります
Juan Mendes


ここで私の回答を参照してください:stackoverflow.com/a/36155560/3894981

回答:


49

最初に、関数名xssRequestを実行すると、クロスサイトリクエストを試行しているように見えます。これが正しい場合、iframeのコンテンツを読み取ることができなくなります。

一方、iframeのURLがドメインにある場合は本文にアクセスできますが、タイムアウトを使用してiframeを削除すると、コールバックが正常に機能することがわかりました。

// possibly excessive use of jQuery - but I've got a live working example in production
$('#myUniqueID').load(function () {
  if (typeof callback == 'function') {
    callback($('body', this.contentWindow.document).html());
  }
  setTimeout(function () {$('#frameId').remove();}, 50);
});

4
あなたは置き換えることができ$('body', this.contentWindow.document).html()this.contentDocument.body.outerHTML
サムSoffes

12
jQueryなしでこれを行う方法はありますか?
devios1

6
jQuery 3.0以降、load廃止されました。.on('load', function() { ... })代わりに使用してください。
Doppelganger

36

私はjQueryを使用していますが、驚いたことに、重いページをテストしてロードしただけでロードされているようで、iframeのロードを確認するまで数秒間アラートを受信しませんでした。

$('#the_iframe').load(function(){
    alert('loaded!');
});

したがって、jQueryを使用したくない場合は、ソースコードを調べて、この関数がiframe DOM要素とは異なる動作をするかどうかを確認します。興味があるので、後で自分で調べて、ここに投稿します。また、私は最新のクロムでのみテストしました。


純粋なJavaScriptを使用してDOM要素を作成し、その変数をセレクターとしてjQueryに渡したことに気づきました。おそらくそれが、コードが機能していない理由です。
Neo

12
jQuery 3.0以降、load廃止されました。.on('load', function() { ... })代わりに使用してください。
Doppelganger

8

iframeタグが親ドキュメントのコンテンツを囲まないため、iframeのinnerHTMLは空白です。iframeのsrc属性で参照されるページからコンテンツを取得するには、iframeのcontentDocumentプロパティにアクセスする必要があります。ただし、srcが別のドメインのものである場合は、例外がスローされます。これは、他のユーザーのページで任意のJavaScriptを実行できないようにするセキュリティ機能であり、クロスサイトスクリプティングの脆弱性を引き起こします。ここに私が話していることを説明するいくつかのサンプルコードがあります:

<script src="http://prototypejs.org/assets/2009/8/31/prototype.js" type="text/javascript"></script>

<h1>Parent</h1>

<script type="text/javascript">
function on_load(iframe) {
  try {
    // Displays the first 50 chars in the innerHTML of the
    // body of the page that the iframe is showing.
    // EDIT 2012-04-17: for wider support, fallback to contentWindow.document
    var doc = iframe.contentDocument || iframe.contentWindow.document;
    alert(doc.body.innerHTML.substring(0, 50));
  } catch (e) {
    // This can happen if the src of the iframe is
    // on another domain
    alert('exception: ' + e);
  }
}
</script>
<iframe id="child" src="iframe_content.html" onload="on_load(this)"></iframe>

例をさらに進めるには、これをiframeのコンテンツとして使用してみてください。

<h1>Child</h1>

<a href="http://www.google.com/">Google</a>

<p>Use the preceeding link to change the src of the iframe
to see what happens when the src domain is different from
that of the parent page</p>

1
contentDocumentプロパティはIE 7でサポートされていません。IEもサポートされている可能性があります。IEを処理する方法はwindow ['iframeid']。documentまたはまったく同じwindow.frames ['iframeid']。document証明リンクです。 mozilla.org/en/...
オルガ

7

単語のドキュメントやpdfなどのドキュメントがiframeにストリーミングされていて、うまく機能するソリューションを見つけた場合、私はこれを行わなければなりませんでした。キーはonreadystatechanged、iframeでイベントを処理することです。

フレームの名前が「myIframe」であるとしましょう。まず、コードスタートアップのどこかに(iframeの後の任意の場所でインライン化します)、次のようなものを追加してイベントハンドラーを登録します。

document.getElementById('myIframe').onreadystatechange = MyIframeReadyStateChanged;

iframeでonreadystatechage属性を使用できませんでした。理由は思い出せませんが、アプリはIE 7およびSafari 3で動作する必要があったため、それが要因であった可能性があります。

以下は、完全な状態を取得する方法の例です。

function MyIframeReadyStateChanged()
{
    if(document.getElementById('myIframe').readyState == 'complete')
    {
        // Do your complete stuff here.
    }
}

6

IEフレームのコンテンツがIEに完全に読み込まれたときに、待機中のスピナーdivを非表示にしたかったのですが、Stackoverflow.Comに記載されているすべてのソリューションを文字通り試しましたが、期待どおりに機能しませんでした。

次に、iフレームのコンテンツが完全に読み込まれると、$(Window)loadイベントが発生する可能性があるという考えがありました。そしてそれがまさに何が起こったのか。だから、私はこの小さなスクリプトを書いて、魔法のように働いた:

     $(window).load(function () {
     //alert("Done window ready ");
     var lblWait = document.getElementById("lblWait");
     if (lblWait != null ) {
         lblWait.style.visibility = "false";
         document.getElementById("divWait").style.display = "none";
     }
 });

お役に立てれば。


これは単純な解決策であり、ページ全体がロードされた後にJavaScriptを実行する場合は問題なく機能します。つまり、最初にjs効果なしで完全にロードされたページが表示され、おそらく2〜2秒後に(ロードに応じて)、JavaScriptによって作成された変更が行われます。私は個人的にiframeのサイズを変更しようとしましたが、ページをクリックしてから最初の3秒間画面に注意を払わなければ機能しますが、それ以外の場合(これは私の場合と同様)、コードへのパッチワークとして表示されます。
アンパサンド2015

1
コメントをありがとうございます。ページが読み込まれた後にiframeが読み込まれるようにしたかったので、このソリューションは私のケースでうまく機能しました。
Nada N. Hantouli

2

私はあなたと同じような問題を抱えていました。私がしたことは、jQueryと呼ばれるものを使用することです。次に、JavaScriptコードで行うのは次のとおりです。

$(function(){ //this is regular jQuery code. It waits for the dom to load fully the first time you open the page.

    $("#myIframeId").load(function(){
       callback($("#myIframeId").html());
       $("#myIframeId").remove();

    });

});

HTMLを取得する前にiFrameを削除したようです。今、私はそれに関する問題を見ます:p

お役に立てれば :)。


1

私のプロジェクトには同様に動作する同様のコードがあります。私のコードをあなたの関数に適応させると、解決策は次のようになります:

function xssRequest(url, callback)
{
    var iFrameObj = document.createElement('IFRAME');
    iFrameObj.id = 'myUniqueID';
    document.body.appendChild(iFrameObj);       
    iFrameObj.src = url;                        

    $(iFrameObj).load(function() 
    {
        callback(window['myUniqueID'].document.body.innerHTML);
        document.body.removeChild(iFrameObj);
    });
}

(1つまたは両方の原因):1. body要素に対して使用する必要がある2.ページDOMからiframeを削除した


1

読み込みイベントは正しいと思います。正しくないのは、iframeコンテンツdomからコンテンツを取得する方法です。

必要なのは、iframeオブジェクトのhtmlではなく、iframeに読み込まれたページのhtmlです。

あなたがしなければならないことは、でコンテンツ文書にアクセスすることですiFrameObj.contentDocument。現在のページと同じドメインにある場合、iframe内に読み込まれたページのdomを返します。

iframeを削除する前にコンテンツを取得します。

私はFirefoxとオペラでテストしました。

次に、$(childDom).html()またはでデータを取得できると思います$(childDom).find('some selector') ...


0

私は過去にまったく同じ問題を抱えていましたが、修正する唯一の方法は、iframeページにコールバックを追加することでした。もちろん、これはiframeコンテンツを制御できる場合にのみ機能します。


22
私はあなたに反対票を投じませんでしたが、彼ができないと彼が言ったことを正確に提案したので、あなたは反対票を投じたと思います-彼は具体的に言った-「私はIFRAMEのコンテンツを制御できないので、私はできるそこからコールバックを起動します。」
Dave Haynes、

-1

onloadattrbuteを使用すると、問題が解決します。

例を示します。

function a() {
alert("Your iframe has been loaded");
}
<iframe src="https://stackoverflow.com" onload="a()"></iframe>

これは、あなたの望むことですか?

詳細については、ここをクリックしてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.