Wywołanie zwrotne JavaScript po zakończeniu ładowania ramki IFRAME?

147

Muszę wykonać wywołanie zwrotne, gdy ramka IFRAME zakończy ładowanie. Nie mam kontroli nad zawartością w IFRAME, więc nie mogę stamtąd odpalić wywołania zwrotnego.

Ta ramka IFRAME jest tworzona programowo i muszę przekazać jej dane jako zmienną w wywołaniu zwrotnym, a także zniszczyć ramkę iframe.

Jakieś pomysły?

EDYTOWAĆ:

Oto co mam teraz:

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

To wywołanie zwrotne przed załadowaniem elementu iFrame, więc wywołanie zwrotne nie zwróciło żadnych danych.

FlySwat
źródło
1
Myślę, że nie chcesz dołączać obsługi zdarzeń do samego elementu iframe, ale jest to okno zawartości.
bobwienholt
1
Problem polega na żądaniu między domenami. Nie możesz tego zrobić, jeśli ramka iframe pochodzi z innej domeny
Victor,
W rzeczywistości istnieje zdarzenie load w obiekcie iframe, które jest uruchamiane za każdym razem, gdy element iframe kończy ładowanie dokumentu, w przeciwnym razie musisz podłączyć się do okna po każdym załadowaniu
Juan Mendes
Zobacz także stackoverflow.com/questions/205087/…
ripper234
Zobacz moją odpowiedź tutaj: stackoverflow.com/a/36155560/3894981
gość

Odpowiedzi:

49

Po pierwsze, przechodząc przez nazwę funkcji xssRequest , brzmi to tak, jakbyś próbował wykonać żądanie między witrynami - co jeśli to prawda, nie będziesz w stanie odczytać zawartości elementu iframe.

Z drugiej strony, jeśli adres URL elementu iframe znajduje się w Twojej domenie, możesz uzyskać dostęp do treści, ale odkryłem, że jeśli użyję limitu czasu do usunięcia elementu iframe, wywołanie zwrotne działa dobrze:

// 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
źródło
4
można zastąpić $('body', this.contentWindow.document).html()zthis.contentDocument.body.outerHTML
Sam Soffes
12
Masz jakiś pomysł, jak to zrobić bez jQuery?
devios1
6
Od wersji jQuery 3.0 loadnie ma. Użyj .on('load', function() { ... })zamiast tego.
Doppelganger
36

Używam jQuery i, co zaskakujące, wygląda na to, że ładuje się, ponieważ właśnie przetestowałem i załadowałem ciężką stronę i nie otrzymałem ostrzeżenia przez kilka sekund, dopóki nie zobaczyłem ładowania iframe:

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

Więc jeśli nie chcesz używać jQuery, spójrz na ich kod źródłowy i zobacz, czy ta funkcja zachowuje się inaczej z elementami iframe DOM, przyjrzę się temu później, ponieważ jestem zainteresowany i opublikuję tutaj. Testowałem też tylko w najnowszym chrome.

Neo
źródło
Zauważyłem, że utworzyłeś element DOM za pomocą czystego javascript, a następnie przekazałeś tę zmienną do jQuery jako selektor, może dlatego kod nie działa?
Neo
12
Od wersji jQuery 3.0 loadnie ma. Użyj .on('load', function() { ... })zamiast tego.
Doppelganger
8

Wewnętrzny kod HTML elementu iframe jest pusty, ponieważ tag iframe nie otacza żadnej treści w dokumencie nadrzędnym. Aby pobrać treść ze strony, do której odwołuje się atrybut src elementu iframe, musisz uzyskać dostęp do właściwości contentDocument elementu iframe. Jednak wyjątek zostanie zgłoszony, jeśli źródło pochodzi z innej domeny. Jest to funkcja bezpieczeństwa, która uniemożliwia wykonanie dowolnego kodu JavaScript na czyjejś stronie, co spowodowałoby lukę w zabezpieczeniach skryptów między witrynami. Oto przykładowy kod ilustrujący to, o czym mówię:

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

Aby rozwinąć przykład, spróbuj użyć tego jako zawartości elementu 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>
allyourcode
źródło
1
Właściwość contentDocument nie jest obsługiwana przez IE 7 i może więcej IE, sposobem radzenia sobie z IE jest okno ['iframeid']. dokument lub dokładnie to samo window.frames ['iframeid']. dowód dokumentu link tutaj programista. mozilla.org/en/…
Olga
7

Musiałem to zrobić w przypadkach, gdy dokumenty takie jak Word docs i PDF były przesyłane strumieniowo do iframe i znalazłem rozwiązanie, które działa całkiem dobrze. Kluczem jest obsługa onreadystatechangedzdarzenia w elemencie iframe.

Powiedzmy, że nazwa Twojej ramki to „myIframe”. Najpierw gdzieś podczas uruchamiania kodu (robię to w dowolnym miejscu po elemencie iframe) dodaj coś takiego, aby zarejestrować procedurę obsługi zdarzeń:

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

Nie mogłem użyć atrybutu onreadystatechage w iframe, nie pamiętam dlaczego, ale aplikacja musiała działać w IE 7 i Safari 3, więc może to być czynnik.

Oto przykład, jak uzyskać pełny stan:

function MyIframeReadyStateChanged()
{
    if(document.getElementById('myIframe').readyState == 'complete')
    {
        // Do your complete stuff here.
    }
}
Ryan Cook
źródło
6

Chciałem ukryć czekający spinner div, gdy zawartość i frame jest w pełni załadowana w IE, próbowałem dosłownie każdego rozwiązania wymienionego w Stackoverflow.Com, ale nic nie działało tak, jak chciałem.

Wtedy wpadłem na pomysł, że gdy zawartość i-frame zostanie w pełni załadowana, zdarzenie ładowania $ (Window) może zostać uruchomione. I tak właśnie się stało. Napisałem więc ten mały skrypt i działałem jak magia:

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

Mam nadzieję że to pomoże.

Nada N. Hantouli
źródło
jest to proste rozwiązanie i działa dobrze, jeśli chcesz, aby skrypt javascript był wykonywany PO załadowaniu całej strony. oznacza to, że najpierw zobaczysz w pełni załadowaną stronę, bez efektu js, a po może sekundach lub dwóch (w zależności od obciążenia) wszelkie zmiany wprowadzone przez javascript będą miały miejsce. Osobiście próbowałem zmienić rozmiar mojego elementu iframe i działa, jeśli nie zwracasz uwagi na ekran przez pierwsze trzy sekundy po kliknięciu strony, ale w przeciwnym razie może (tak jak w moim przypadku) pojawić się jako patchwork do kodu.
ampersands
1
dziękuję za komentarz, to rozwiązanie działało świetnie w moim przypadku, ponieważ chciałem, aby iframe został załadowany po załadowaniu strony.
Nada N. Hantouli
2

Miałem podobny problem jak ty. Zrobiłem, że używam czegoś, co nazywa się jQuery. To, co następnie robisz w kodzie javascript, jest następujące:

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

    });

});

Wygląda na to, że usuwasz element iFrame, zanim pobierzesz z niego kod HTML. Teraz widzę z tym problem: s

Mam nadzieję że to pomoże :).

Automatico
źródło
1

Mam podobny kod w swoich projektach, który działa dobrze. Dostosowując mój kod do Twojej funkcji, rozwiązaniem może być:

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

Być może masz pusty innerHTML, ponieważ (jedna lub obie przyczyny): 1. powinieneś użyć go na elemencie body 2. usunąłeś ramkę iframe z DOM strony

Pier Luigi
źródło
1

Myślę, że zdarzenie obciążenia jest właściwe. To, co jest niewłaściwe, to sposób pobierania treści z elementu iframe content dom.

Potrzebujesz kodu HTML strony załadowanej w elemencie iframe, a nie html obiektu iframe.

Musisz uzyskać dostęp do dokumentu treści za pomocą iFrameObj.contentDocument. Zwraca domenę strony załadowanej wewnątrz elementu iframe, jeśli znajduje się w tej samej domenie, co bieżąca strona.

Odzyskałbym zawartość przed usunięciem elementu iframe.

Testowałem w Firefoksie i Operze.

Wtedy myślę, że możesz odzyskać swoje dane za pomocą $(childDom).html()lub$(childDom).find('some selector') ...


źródło
0

W przeszłości miałem dokładnie ten sam problem i jedynym sposobem, w jaki udało mi się go naprawić, było dodanie wywołania zwrotnego do strony iframe. Oczywiście działa to tylko wtedy, gdy masz kontrolę nad zawartością elementu iframe.

roryf
źródło
22
Nie głosowałem na ciebie, ale wyobrażam sobie, że zostałeś odrzucony, ponieważ zasugerowałeś dokładnie to, czego powiedział, że nie może zrobić - powiedział konkretnie: „Nie mam kontroli nad zawartością w IFRAME, więc mogę” t odpalić wywołanie zwrotne z tego miejsca. "
Dave Haynes
-1

Korzystanie z onloadattrbute rozwiąże Twój problem.

Oto przykład.

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

Czy to jest to, czego chcesz?

Kliknij tutaj, aby uzyskać więcej informacji.


źródło