Javascript-Rückruf, wenn IFRAME vollständig geladen ist?

147

Ich muss einen Rückruf ausführen, wenn ein IFRAME vollständig geladen wurde. Ich habe keine Kontrolle über den Inhalt im IFRAME, daher kann ich den Rückruf von dort nicht auslösen.

Dieser IFRAME wird programmgesteuert erstellt, und ich muss seine Daten als Variable im Rückruf übergeben und den Iframe zerstören.

Irgendwelche Ideen?

BEARBEITEN:

Folgendes habe ich jetzt:

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);
    });
}

Dieser Rückruf erfolgt vor dem Laden des iFrame, sodass für den Rückruf keine Daten zurückgegeben werden.

FlySwat
quelle
1
Ich denke, Sie möchten den Ereignishandler nicht an den Iframe selbst anhängen, sondern an dessen Inhaltsfenster.
Bobwienholt
1
Das Problem ist die domänenübergreifende Anforderung. Sie können es nicht tun, wenn der Iframe von einer anderen Domain stammt
Victor
Tatsächlich gibt es ein Ladeereignis für das iframe-Objekt, das jedes Mal ausgelöst wird, wenn der iframe das Laden eines Dokuments beendet hat. Andernfalls müssen Sie sich nach jedem Laden an das Fenster anschließen
Juan Mendes,
Siehe meine Antwort hier: stackoverflow.com/a/36155560/3894981
Alter

Antworten:

49

Zunächst wird der Funktionsname xssRequest verwendet Sie zunächst , klingt es so, als würden Sie eine standortübergreifende Anforderung versuchen. Wenn dies richtig ist, können Sie den Inhalt des nicht lesen.

Wenn sich die URL des Iframes in Ihrer Domain befindet, können Sie auf den Text zugreifen. Ich habe jedoch festgestellt, dass der Rückruf einwandfrei funktioniert, wenn ich zum Entfernen des Iframes eine Zeitüberschreitung verwende:

// 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);
});
Remy Sharp
quelle
4
Sie könnten ersetzen $('body', this.contentWindow.document).html()durchthis.contentDocument.body.outerHTML
Sam Soffes
12
Irgendeine Idee, wie man das ohne jQuery macht?
Devios1
6
Ab jQuery 3.0 loadist weg. Bitte verwenden Sie .on('load', function() { ... })stattdessen.
Doppelgänger
35

Ich verwende jQuery und überraschenderweise scheint dies geladen zu werden, da ich gerade eine schwere Seite getestet und geladen habe und die Warnung einige Sekunden lang nicht erhalten habe, bis ich das Laden des Iframes sah:

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

Wenn Sie jQuery nicht verwenden möchten, schauen Sie sich den Quellcode an und prüfen Sie, ob sich diese Funktion bei iframe-DOM-Elementen anders verhält. Ich werde sie später selbst betrachten, da ich interessiert bin, und hier posten. Auch habe ich nur im neuesten Chrom getestet.

Neo
quelle
Ich habe festgestellt, dass Sie das DOM-Element mit reinem Javascript erstellt und diese Variable dann als Selektor an jQuery übergeben haben. Vielleicht funktioniert Ihr Code deshalb nicht?
Neo
12
Ab jQuery 3.0 loadist weg. Bitte verwenden Sie .on('load', function() { ... })stattdessen.
Doppelgänger
8

Das innerHTML Ihres Iframes ist leer, da Ihr Iframe-Tag keinen Inhalt im übergeordneten Dokument umgibt. Um den Inhalt von der Seite abzurufen, auf die das src-Attribut des iframes verweist, müssen Sie auf die contentDocument-Eigenschaft des iframes zugreifen. Eine Ausnahme wird ausgelöst, wenn der Quellcode aus einer anderen Domäne stammt. Dies ist eine Sicherheitsfunktion, die verhindert, dass Sie beliebiges JavaScript auf der Seite einer anderen Person ausführen, wodurch eine Sicherheitsanfälligkeit bezüglich Cross-Site-Scripting entsteht. Hier ist ein Beispielcode, der veranschaulicht, wovon ich spreche:

<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>

Verwenden Sie dies als Inhalt des Iframes, um das Beispiel weiterzuentwickeln:

<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>
allyourcode
quelle
1
Die contentDocument-Eigenschaft wird von IE 7 nicht unterstützt, und möglicherweise auch mehr IE. Der Umgang mit IE ist window ['iframeid']. document oder genau das gleiche window.frames ['iframeid']. document Proof Link hier Entwickler. mozilla.org/en/…
Olga
7

Ich musste dies in Fällen tun, in denen Dokumente wie Word-Dokumente und PDFs zum Iframe gestreamt wurden und eine Lösung gefunden wurden, die ziemlich gut funktioniert. Der Schlüssel ist die Handhabung deronreadystatechanged Ereignis im Iframe.

Nehmen wir an, der Name Ihres Frames lautet "myIframe". Fügen Sie zuerst irgendwo in Ihrem Code-Start (ich mache es inline irgendwo nach dem Iframe) so etwas hinzu, um den Event-Handler zu registrieren:

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

Ich konnte kein onreadystatechage-Attribut für den Iframe verwenden. Ich kann mich nicht erinnern, warum, aber die App musste in IE 7 und Safari 3 funktionieren, sodass dies möglicherweise ein Faktor war.

Hier ist ein Beispiel, wie Sie den vollständigen Status erhalten:

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

Ich wollte das wartende Spinner-Div ausblenden, wenn der i-Frame-Inhalt vollständig im IE geladen ist. Ich habe buchstäblich jede in Stackoverflow.Com erwähnte Lösung ausprobiert, aber nichts hat so funktioniert, wie ich es wollte.

Dann hatte ich die Idee, dass das Ladeereignis $ (Window) ausgelöst werden könnte, wenn der Inhalt des i-Frames vollständig geladen ist. Und genau das ist passiert. Also schrieb ich dieses kleine Skript und arbeitete wie Magie:

     $(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";
     }
 });

Hoffe das hilft.

Nada N. Hantouli
quelle
Dies ist eine einfache Lösung und funktioniert einwandfrei, wenn Sie möchten, dass Ihr Javascript ausgeführt wird, nachdem die gesamte Seite geladen wurde. Dies bedeutet, dass Sie zuerst die vollständig geladene Seite ohne js-Effekt sehen und nach ein oder zwei Sekunden (abhängig vom Laden) alle Änderungen, die durch das Javascript erstellt werden, dann erfolgen. Ich persönlich habe versucht, die Größe meines Iframes zu ändern, und es funktioniert, wenn Sie in den ersten drei Sekunden nach dem Klicken auf eine Seite nicht auf den Bildschirm achten, dies jedoch (wie in meinem Fall) als Patchwork für den Code angezeigt wird.
kaufmännisches Und
1
Vielen Dank für Ihren Kommentar. Diese Lösung hat in meinem Fall hervorragend funktioniert, da ich wollte, dass der Iframe nach dem Laden der Seite geladen wird.
Nada N. Hantouli
2

Ich hatte ein ähnliches Problem wie Sie. Was ich getan habe ist, dass ich etwas benutze, das jQuery heißt. Was Sie dann im Javascript-Code tun, ist Folgendes:

$(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();

    });

});

Es scheint, als würden Sie Ihren iFrame löschen, bevor Sie den HTML-Code daraus abrufen. Jetzt sehe ich ein Problem damit: p

Hoffe das hilft :).

Automatico
quelle
1

Ich habe einen ähnlichen Code in meinen Projekten, der gut funktioniert. Wenn Sie meinen Code an Ihre Funktion anpassen, könnte dies eine Lösung sein:

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);
    });
}

Möglicherweise haben Sie eine leere innerHTML, weil (eine oder beide Ursachen): 1. Sie sollten sie gegen das body-Element verwenden. 2. Sie haben den iframe aus dem DOM Ihrer Seite entfernt

Pier Luigi
quelle
1

Ich denke, das Ladeereignis ist richtig. Was nicht richtig ist, ist die Art und Weise, wie Sie den Inhalt von iframe content dom abrufen.

Was Sie brauchen, ist das HTML der Seite, die in den Iframe geladen wird, nicht das HTML des Iframe-Objekts.

Sie müssen lediglich mit auf das Inhaltsdokument zugreifen iFrameObj.contentDocument . Dies gibt den Dom der Seite zurück, die in den Iframe geladen wurde, wenn er sich in derselben Domain der aktuellen Seite befindet.

Ich würde den Inhalt abrufen, bevor ich den Iframe entferne.

Ich habe in Firefox und Oper getestet.

Dann denke ich, dass Sie Ihre Daten mit $(childDom).html()oder abrufen können$(childDom).find('some selector') ...


quelle
0

Ich hatte in der Vergangenheit genau das gleiche Problem und konnte es nur beheben, indem ich den Rückruf zur iframe-Seite hinzufügte. Das funktioniert natürlich nur, wenn Sie die Kontrolle über den Iframe-Inhalt haben.

roryf
quelle
22
Ich habe Sie nicht abgelehnt, aber ich kann mir vorstellen, dass Sie abgelehnt wurden, weil Sie genau vorgeschlagen haben, was er gesagt hat, dass er nicht kann - er hat ausdrücklich gesagt: "Ich habe keine Kontrolle über den Inhalt im IFRAME, also kann ich." t den Rückruf von dort abfeuern. "
Dave Haynes
-1

Verwenden von onload attrbute löst Ihr Problem.

Hier ist ein Beispiel.

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

Ist das was du willst?

Klicken Sie hier für weitere Informationen.


quelle