Wie überprüfe ich, ob iframe geladen ist oder einen Inhalt hat?

83

Ich habe einen Iframe mit id = "myIframe" und hier meinen Code zum Laden des Inhalts:

$('#myIframe').attr("src", "my_url");

Das Problem ist, dass das Laden manchmal zu lange dauert und manchmal sehr schnell. Also muss ich die Funktion "setTimeout" verwenden:

setTimeout(function(){
   if (//something shows iframe is loaded or has content)
   {
       //my code
   }
   else
   {
       $('#myIframe').attr("src",""); //stop loading content
   }
},5000);

Ich möchte nur wissen, wie ich herausfinden kann, ob ein iFrame geladen ist oder Inhalt enthält. Die Verwendung iframe.contents().find()funktioniert nicht. Ich kann nicht verwenden iframe.load(function(){}).

Neuling29
quelle
Sie möchten also nicht, dass der Iframe etwas lädt, wenn das Laden länger als 5 Sekunden dauert?
Skimberk1
Danke für Ihre Hilfe :) . Ja, ich möchte nichts vom iframe laden, wenn das Laden länger als 5 Sekunden dauert. Die Verwendung von ".ready ()", wie Sie unten zeigen, funktioniert nicht.
Neuling 29
Siehe meine Antwort hier stackoverflow.com/questions/17158932/…
Alter
Überprüfen Sie diese Antwort - forums.tumult.com/t/detect-iframe-loaded/7588
Varshaan

Antworten:

87

Versuche dies.

<script>
function checkIframeLoaded() {
    // Get a handle to the iframe element
    var iframe = document.getElementById('i_frame');
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

    // Check if loading is complete
    if (  iframeDoc.readyState  == 'complete' ) {
        //iframe.contentWindow.alert("Hello");
        iframe.contentWindow.onload = function(){
            alert("I am loaded");
        };
        // The loading is complete, call the function we want executed once the iframe is loaded
        afterLoading();
        return;
    } 

    // If we are here, it is not loaded. Set things up so we check   the status again in 100 milliseconds
    window.setTimeout(checkIframeLoaded, 100);
}

function afterLoading(){
    alert("I am here");
}
</script>

<body onload="checkIframeLoaded();"> 
Biranchi
quelle
21
Fehler beim Übergeben einer Zeichenfolge an setTimeout (). Es ist sauberer, eine Funktionsreferenz zu übergeben:setTimeout(checkIframeLoaded, 100);
Jesse Hallett
1
Dies führte zu "Unsicherer JavaScript-Versuch, auf Frame mit URL url1 von Frame mit URL2 zuzugreifen. Domänen, Protokolle und Ports müssen übereinstimmen."
Mohamed-Ibrahim
Dies war die beste Lösung für das, was ich erreichen wollte. Ich verwende AngularJS im iFrame und ng-include, wodurch das Laden der enthaltenen Dateien verzögert wird. Ich habe versucht, den Inhalt des Iframes beim Onload-Ereignis zu drucken, aber es wurde zu früh ausgelöst. Die Überprüfung auf readyState === "complete"hat den Trick ausgeführt, da er sich erst ändert, wenn alles geladen ist.
Jeffrey A. Gochin
3
Ich muss sagen, dass dies die einzige Lösung war, die auch für mich funktioniert hat. Sie können nicht nur dem Ladeereignis auf einem Iframe vertrauen, da sie sofort in den meisten Fällen auf IE11 feuern, Chrome und Rande mit der iframe.contentDocument.location.hrefDarstellung , wie about:blank. Dies scheint auch dann der Fall zu sein, wenn das srcfür das iframedirekt im HTML angegeben ist.
Rmalayter
21
Dies wird nicht funktionieren, wenn der Iframe von einer anderen Domain stammt:VM29320:1 Uncaught DOMException: Blocked a frame with origin "http://localhost:9002" from accessing a cross-origin frame.
Augustin Riedinger
45

Bitte verwenden Sie:

$('#myIframe').on('load', function(){
    //your code (will be called once iframe is done loading)
});

Meine Antwort wurde aktualisiert, als sich die Standards änderten.

Pratikabu
quelle
5
Das Aufrufen von .load ist jetzt veraltet. Verwenden Sie stattdessen .on ('load', function () {})
Graham T
51
Das Aufrufen von jQuery ist jetzt veraltet ^^
cchamberlain
4
Dieser Ansatz funktioniert überhaupt nicht, da das Ereignis sofort ausgelöst wird, da iframes im Allgemeinen mit beginnt src="about:blank", selbst wenn das srcdirekt im HTML- iframeCode angegeben ist oder bevor ein Knoten zum DOM hinzugefügt wird. Ich habe dies getestet, indem ich in einer engen Schleife auf IE11, Chrome und Edge nach den iframe's contentDocument.location.hrefabgefragt habe. Es funktioniert auch nicht, wenn der gerahmte Inhalt über Meta-Tags oder Javascript umgeleitet wird.
Rmalayter
17

Ich hatte das gleiche Problem und fügte hinzu, ich musste überprüfen, ob iframe geladen ist, unabhängig von der domänenübergreifenden Richtlinie. Ich habe eine Chrome-Erweiterung entwickelt, die ein bestimmtes Skript in eine Webseite einfügt und Inhalte von der übergeordneten Seite in einem Iframe anzeigt. Ich habe versucht, dem Ansatz zu folgen, und das hat perfekt für mich funktioniert.
PS: In meinem Fall habe ich die Kontrolle über den Inhalt im Iframe, aber nicht auf der übergeordneten Site. (Iframe wird auf meinem eigenen Server gehostet.)

Erstens:
Erstellen Sie einen data- Iframe mit einem Attribut wie (dieser Teil war in meinem Fall in einem injizierten Skript).
<iframe id="myiframe" src="http://anyurl.com" data-isloaded="0"></iframe>

Verwenden Sie nun im Iframe-Code:

var sourceURL = document.referrer;
window.parent.postMessage('1',sourceURL);



Nun zurück zum injizierten Skript gemäß meinem Fall:

setTimeout(function(){
  var myIframe = document.getElementById('myiframe');
  var isLoaded = myIframe.prop('data-isloaded');
  if(isLoaded != '1')
  {
    console.log('iframe failed to load');
  } else {
    console.log('iframe loaded');
  }
},3000);


und,

window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
    if(event.origin !== 'https://someWebsite.com') //check origin of message for security reasons
    {
        console.log('URL issues');
        return;
    }
    else {
        var myMsg = event.data;
        if(myMsg == '1'){
            //8-12-18 changed from 'data-isload' to 'data-isloaded
            $("#myiframe").prop('data-isloaded', '1');
        }
    }           
}



Es mag die Frage nicht genau beantworten, aber es ist tatsächlich ein möglicher Fall dieser Frage, den ich mit dieser Methode gelöst habe.

Tushar Shukla
quelle
Es gibt einige Fehler in Ihrem Code, wie document.getElement-> s <-ById, aber die ganze Idee ist nützlich. Es klappt. Danke)
JohnK
@ JohnK Danke, dass du darauf hingewiesen hast, ich habe es behoben. Ich bin froh zu wissen, dass dies für Sie nützlich ist.
Tushar Shukla
12

Einfachste Option:

<script type="text/javascript">
  function frameload(){
   alert("iframe loaded")
  }
</script>

<iframe onload="frameload()" src=...>
Orane
quelle
10
Keine solide Lösung, da sie den Alarm ausgibt, selbst wenn die URL fehlerhaft ist.
Bboy
7

Sie können das loadEreignis des Iframes verwenden , um zu reagieren, wenn der Iframe geladen wird.

document.querySelector('iframe').onload = function(){
    console.log('iframe loaded');
};

Dies sagt Ihnen nicht, ob der richtige Inhalt geladen wurde: Um dies zu überprüfen, können Sie den überprüfen contentDocument.

document.querySelector('iframe').onload = function(){
    var iframeBody = this.contentDocument.body;
    console.log('iframe loaded, body is: ', body);
};

Das Überprüfen von contentDocumentfunktioniert nicht, wenn der Iframe srcauf eine andere Domäne verweist, in der Ihr Code ausgeführt wird.

Max Heiber
quelle
2
Bitte überlegen Sie, Ihren Beitrag zu bearbeiten, um weitere Erklärungen darüber zu erhalten, was Ihr Code tut und warum er das Problem löst. Eine Antwort, die meistens nur Code enthält (auch wenn sie funktioniert), hilft dem OP normalerweise nicht, ihr Problem zu verstehen.
SuperBiasedMan
5

Ich bin nicht sicher, ob Sie erkennen können, ob es geladen ist oder nicht, aber Sie können ein Ereignis auslösen, sobald es geladen ist:

$(function(){
    $('#myIframe').ready(function(){
        //your code (will be called once iframe is done loading)
    });
});

EDIT: Wie von Jesse Hallett hervorgehoben, wird dies immer ausgelöst, wenn das iframegeladen hat, auch wenn es bereits geladen hat. Wenn also der iframebereits geladen wurde, wird der Rückruf im Wesentlichen sofort ausgeführt.

skimberk1
quelle
2
Das Schöne an dieser Methode ist, dass das jQuery-Ereignis 'ready' auch dann ausgelöst wird, wenn Sie es binden, nachdem der iframe vollständig geladen wurde. Auf diese Weise können Sie überprüfen, ob der Iframe bereits Inhalt enthält, oder Sie benachrichtigen, wenn er Inhalt erhält.
Jesse Hallett
1
Dies scheint nur einmal für den Iframe ausgelöst zu werden. Wenn Ihr Iframe jedoch Links enthält, die dazu führen können, dass der Inhalt des Iframes neu geladen wird, wird dieses Ereignis nicht erneut ausgelöst. Wenn dies Ihr Fall ist, dann verwenden Sie die Antwort von @pratikabu -$('#myIframe').load(function(){ })
ragamufin
@ skimberk1 Hallo, gemäß dieser Antwort funktioniert Ihre Lösung nicht, da jquery eine Variable enthält, die sich daran erinnert, ob das DOM geladen wurde, und nur das aktuelle DOM des aktuellen Frames überprüft, nicht das DOM des Iframes.
Marco Medrano
Ja, Sie können Ereignisse
auslösen
Gemäß diesem Ticket: dev.jquery.com/ticket/5511 , das readyeinen Iframe verwendet , führt die Funktion immer sofort aus, da sie für andere Dokumente als den Frame, in dem jQuery ausgeführt wird, nicht unterstützt wird.
Alter
5

In meinem Fall war es ein Cross-Origin-Frame und wurde manchmal nicht geladen. Die Lösung, die für mich funktioniert hat, lautet: Wenn es erfolgreich geladen wurde, versuchen Sie diesen Code:

var iframe = document.getElementsByTagName('iframe')[0];
console.log(iframe.contentDocument);

Sie können nicht auf contentDocumenteinen Cross-Origin-Fehler zugreifen und diesen auslösen. Wenn der Frame jedoch nicht erfolgreich geladen wurde, contentDocumentwird ein #documentObjekt zurückgegeben

Raza Ahmed
quelle
2

Wenn ein iFrame geladen wird, enthält er zunächst das #document. Wenn Sie also den Ladezustand überprüfen, können Sie am besten überprüfen, was jetzt vorhanden ist.

if ($('iframe').contents().find('body').children().length > 0) {
    // is loaded
} else {
    // is not loaded
}
Obimod
quelle
6
Dies würde fehlschlagen, wenn es sich auf einer anderen Domain befindet
Funkodebat
Dies ist falsch, da sich ein Iframe möglicherweise im Ladevorgang befindet (nicht vollständig geladen).
Mike Shiyan
1

Ich habe einen Trick, der wie folgt funktioniert: [Cross-Browser nicht getestet!]

Definieren Sie den Onload-Ereignishandler von iframe, definiert als

$('#myIframe').on('load', function() {
    setTimeout(function() {
        try {
            console.log($('#myIframe')[0].contentWindow.document);
        } catch (e) {
            console.log(e);
            if (e.message.indexOf('Blocked a frame with origin') > -1 || e.message.indexOf('from accessing a cross-origin frame.') > -1) {
                alert('Same origin Iframe error found!!!');
                //Do fallback handling if you want here
            }
        }
    }, 1000);

});

Haftungsausschluss: Dies funktioniert nur für Dokumente mit dem gleichen Ursprung wie IFRAME.

Pratap Singh
quelle
0

Eine wirklich gute Methode ist die Verwendung von jQuery AJAX. Der übergeordnete Frame würde folgendermaßen aussehen:

<iframe src="iframe_load.php" style="width: 100%; height: 100%;"></iframe>

Die Datei iframe_load.php lädt die jQuery-Bibliothek und ein JavaScript, das versucht, die Ziel-URL in ein AJAX GET zu laden:

var the_url_to_load = "http://www.your-website.com" ;
$.ajax({
            type: "GET",
            url: the_url_to_load,
            data: "",
            success: function(data){
                // if can load inside iframe, load the URL
                location.href = the_url_to_load ;
            },
            statusCode: {
                500: function() {
                    alert( 'site has errors' ) ;
                }
            },
            error:function (xhr, ajaxOptions, thrownError){
                // if x-frame-options, site is down or web server is down
                alert( 'URL did not load due to x-frame-options' ) ;
            } });

WICHTIG Das Ziel muss den Header "Access-Control-Allow-Origin" enthalten. Beispiel in PHP:

HEADER( "Access-Control-Allow-Origin: *" ) ;
Nate Skate
quelle
0

Wenn Sie wissen müssen, wann der Iframe manipulationsbereit ist, verwenden Sie ein Intervall. In diesem Fall habe ich „ping“ der Inhalt alle 250 ms und wenn es irgendwelche Inhalte innerhalb Ziel iframe, die „ping“ stoppen und etwas tun.

var checkIframeLoadedInterval = setInterval( checkIframeLoaded, 250 );

function checkIframeLoaded() {
    var iframe_content = $('iframe').contents();

    if (iframe_content.length > 0) {
        clearInterval(checkIframeLoadedInterval);

        //Apply styles to the button
        setTimeout(function () {
            //Do something inside the iframe 
            iframe_content.find("body .whatever").css("background-color", "red");
        }, 100); //100 ms of grace time
    }
}
Jimmy Adaro
quelle
0

Wenn Sie die Seite und den Iframe in derselben Domain hosten , können Sie auf das Window.DOMContentLoadedEreignis des Iframes warten . Sie müssen warten, bis die Originalseite ausgelöst wird, DOMContentLoadedund dann einen DOMContentLoadedEreignis-Listener an den Iframe anhängen Window.

Vorausgesetzt, Sie haben einen Iframe wie folgt:

<iframe id="iframe-id" name="iframe-name" src="..."></iframe>

Mit dem nächsten Snippet können Sie sich in das DOMContentLoadedEreignis des Iframes einbinden :

document.addEventListener('DOMContentLoaded', function () {
    var iframeWindow = frames['iframe-name'];
    // var iframeWindow = document.querySelector('#iframe-id').contentWindow
    // var iframeWindow = document.getElementById('iframe-id').contentWindow

    iframeWindow.addEventListener('DOMContentLoaded', function () {
        console.log('iframe DOM is loaded!');
    });
});
Daniel
quelle