Richiamata Javascript al termine del caricamento di IFRAME?


147

Devo eseguire una richiamata quando un IFRAME ha terminato il caricamento. Non ho alcun controllo sul contenuto di IFRAME, quindi non posso attivare la richiamata da lì.

Questo IFRAME è creato a livello di codice e devo passare i suoi dati come variabile nel callback, oltre a distruggere l'iframe.

Qualche idea?

MODIFICARE:

Ecco quello che ho ora:

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

Questa richiamata prima del caricamento dell'iFrame, quindi la richiamata non ha restituito dati.


1
Penso che non desideri collegare il gestore eventi all'iframe stesso ma è la finestra dei contenuti.
bobwienholt,

1
Il problema è la richiesta tra domini. Non puoi farlo se l'iframe proviene da un altro dominio
Victor,

In realtà, c'è un evento di caricamento sull'oggetto iframe che si attiva ogni volta che l'iframe finisce di caricare un documento, altrimenti, dopo ogni caricamento dovrai collegarti alla finestra
Juan Mendes,


Vedi la mia risposta qui: stackoverflow.com/a/36155560/3894981
amico

Risposte:


49

Innanzitutto, andando con il nome della funzione xssRequest sembra che tu stia provando una richiesta cross site - che se è giusto, non sarai in grado di leggere il contenuto dell'iframe.

D'altra parte, se l'URL dell'iframe si trova sul tuo dominio puoi accedere al corpo, ma ho scoperto che se uso un timeout per rimuovere l'iframe il callback funziona bene:

// 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
potresti sostituirlo $('body', this.contentWindow.document).html()conthis.contentDocument.body.outerHTML
Sam Soffes,

12
Qualche idea su come farlo senza jQuery?
devios1

6
A partire da jQuery 3.0, non loadc'è più. Si prega di utilizzare .on('load', function() { ... })invece.
Doppelganger,

36

Sto usando jQuery e sorprendentemente questo sembra caricarsi mentre ho appena testato e caricato una pagina pesante e non ho ricevuto l'avviso per alcuni secondi fino a quando non ho visto il caricamento iframe:

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

Quindi se non vuoi usare jQuery dai un'occhiata al loro codice sorgente e vedi se questa funzione si comporta in modo diverso con gli elementi iframe DOM, lo vedrò io stesso quando sono interessato e pubblicherò qui. Inoltre ho testato solo nell'ultimo chrome.


Ho notato che hai creato l'elemento DOM con javascript puro e poi hai passato quella variabile a jQuery come selettore, forse è per questo che il tuo codice non funziona?
Neo,

12
A partire da jQuery 3.0, non loadc'è più. Si prega di utilizzare .on('load', function() { ... })invece.
Doppelganger,

8

InnerHTML del tuo iframe è vuoto perché il tag iframe non racchiude alcun contenuto nel documento principale. Per ottenere il contenuto dalla pagina a cui fa riferimento l'attributo src dell'iframe, è necessario accedere alla proprietà contentDocument dell'iframe. Verrà comunque generata un'eccezione se src proviene da un dominio diverso. Questa è una funzionalità di sicurezza che ti impedisce di eseguire JavaScript arbitrario sulla pagina di qualcun altro, creando una vulnerabilità di scripting tra siti. Ecco un esempio di codice che illustra di cosa sto parlando:

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

Per approfondire l'esempio, prova a usarlo come contenuto dell'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
La proprietà contentDocument non è supportata da IE 7 e forse anche più IE, il modo di gestire IE è il documento window ['iframeid']. o quello che è esattamente lo stesso window.frames ['iframeid'] . mozilla.org/it/…
Olga,

7

Ho dovuto farlo in casi in cui documenti come documenti Word e PDF venivano trasmessi in streaming all'iframe e ho trovato una soluzione che funziona abbastanza bene. La chiave sta gestendo l' onreadystatechangedevento sull'iframe.

Diciamo che il nome della cornice è "myIframe". Prima da qualche parte nel tuo avvio del codice (lo faccio in linea in qualsiasi punto dopo l'iframe) aggiungi qualcosa di simile per registrare il gestore eventi:

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

Non sono stato in grado di utilizzare un attributo onreadystatechage sull'iframe, non ricordo il perché, ma l'app doveva funzionare in IE 7 e Safari 3, quindi potrebbe essere stato un fattore.

Ecco un esempio di come ottenere lo stato completo:

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

6

Volevo nascondere il div in attesa dello spinner quando il contenuto di i frame è completamente caricato su IE, ho provato letteralmente ogni soluzione menzionata in Stackoverflow.Com, ma con niente ha funzionato come volevo.

Poi ho avuto l'idea che quando il contenuto di i frame fosse completamente caricato, l'evento $ (Window) load potesse essere generato. E questo è esattamente quello che è successo. Quindi, ho scritto questa piccola sceneggiatura e ho lavorato come per 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";
     }
 });

Spero che questo ti aiuti.


questa è una soluzione semplice e funziona bene se vuoi che il tuo javascript sia eseguito DOPO che l'intera pagina sia caricata. questo significa che per prima cosa vedi la pagina completamente caricata, senza effetto js, ​​e dopo forse un secondo o due (a seconda del carico) accadranno tutte le modifiche create dal javascript. Personalmente ho provato a ridimensionare il mio iframe, e funziona se non presti attenzione allo schermo per i primi tre secondi dopo aver fatto clic su una pagina, ma questo potrebbe (come nel mio caso) apparire come un patchwork al codice.
commerciali

1
grazie per il tuo commento, questa soluzione ha funzionato perfettamente nel mio caso, poiché volevo che l'iframe fosse caricato dopo che la pagina veniva caricata.
Nada N. Hantouli,

2

Ho avuto un problema simile al tuo. Quello che ho fatto è che uso qualcosa chiamato jQuery. Quello che poi fai nel codice javascript è questo:

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

    });

});

Sembra che tu elimini iFrame prima di prendere l'html da esso. Ora vedo un problema con questo: p

Spero che questo ti aiuti :).


1

Ho un codice simile nei miei progetti che funziona bene. Adattando il mio codice alla tua funzione, una soluzione potrebbe essere la seguente:

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

Forse hai un HTML interno vuoto perché (una o entrambe le cause): 1. dovresti usarlo contro l'elemento body 2. hai rimosso l'iframe dal DOM della tua pagina


1

Penso che l'evento load sia giusto. Ciò che non è giusto è il modo in cui usi per recuperare il contenuto dalla dom dei contenuti iframe.

Ciò di cui hai bisogno è l'html della pagina caricata nell'iframe non l'html dell'oggetto iframe.

Quello che devi fare è accedere al documento di contenuto con iFrameObj.contentDocument . Ciò restituisce la dom della pagina caricata all'interno dell'iframe, se si trova sullo stesso dominio della pagina corrente.

Vorrei recuperare il contenuto prima di rimuovere l'iframe.

Ho testato su Firefox e Opera.

Quindi penso che puoi recuperare i tuoi dati con $(childDom).html()o$(childDom).find('some selector') ...


0

Ho avuto esattamente lo stesso problema in passato e l'unico modo per trovarlo è stato quello di aggiungere il callback nella pagina iframe. Ovviamente funziona solo quando hai il controllo sul contenuto di iframe.


22
Non ti ho votato per difetto, ma immagino che tu abbia votato per difetto perché hai suggerito esattamente quello che ha detto che non può fare - ha detto specificamente: "Non ho alcun controllo sul contenuto dell'IFRAME, quindi posso ' t licenzia il callback da lì. "
Dave Haynes,

-1

utilizzando onload attrbute risolverà il tuo problema.

Ecco un esempio

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

È questo che vuoi?

Clicca qui per maggiori informazioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.