Invocazione del codice JavaScript in un iframe dalla pagina padre

Fondamentalmente, ho un iframe incorporato in una pagina e l’ iframe ha alcune routine JavaScript che devo richiamare dalla pagina padre.

Ora il contrario è abbastanza semplice in quanto è sufficiente chiamare parent.functionName() , ma sfortunatamente, ho bisogno esattamente del contrario.

Si noti che il mio problema non sta cambiando l’ URL di origine iframe , ma richiamando una funzione definita iframe .

Supponi che l’ID del tuo iFrame sia “targetFrame” e che la funzione che vuoi chiamare sia targetFunction() :

 document.getElementById('targetFrame').contentWindow.targetFunction(); 

Puoi anche accedere al frame usando window.frames invece di document.getElementById .

 // this option does not work in most of latest versions of chrome and Firefox window.frames[0].frameElement.contentWindow.targetFunction(); 

Ci sono alcuni capricci di cui essere a conoscenza qui.

  1. HTMLIFrameElement.contentWindow è probabilmente il modo più semplice, ma non è una proprietà abbastanza standard e alcuni browser non lo supportano, soprattutto quelli più vecchi. Questo perché lo standard HTML DOM livello 1 non ha nulla da dire sull’object della window .

  2. Puoi anche provare HTMLIFrameElement.contentDocument.defaultView , che un paio di browser meno recenti consentono, ma IE no. Anche così, lo standard non dice esplicitamente di riavere l’object della window , per lo stesso motivo di (1), ma qui puoi prendere alcune versioni aggiuntive del browser se ti interessa.

  3. window.frames['name'] restituendo la finestra è l’interfaccia più vecchia e quindi più affidabile. Ma devi quindi usare un attributo name="..." per poter ottenere un frame per nome, che è leggermente brutto / deprecato / di transizione. ( id="..." sarebbe meglio, ma a IE non piace.)

  4. window.frames[number] è anche molto affidabile, ma conoscere l’indice giusto è il trucco. Puoi farla franca ad es. se sai che hai solo l’iframe sulla pagina.

  5. È del tutto ansible che l’iframe figlio non sia ancora stato caricato, o che qualcos’altro sia andato storto per renderlo inaccessibile. Potresti trovare più semplice invertire il stream delle comunicazioni: cioè, fare in modo che l’iframe window.parent script window.parent al termine del caricamento e sia pronto per essere richiamato. Passando uno dei propri oggetti (ad esempio una funzione di callback) allo script padre, quel genitore può quindi comunicare direttamente con lo script nell’iframe senza doversi preoccupare di quale HTMLIFrameElement è associato.

Chiamare una funzione JS genitore iframe è ansible, ma solo quando sia il padre che la pagina caricati iframe appartengono allo stesso dominio, ad esempio abc.com, ed entrambi utilizzano lo stesso protocollo, ovvero entrambi sono su http:// o https:// .

La chiamata fallirà nei seguenti casi:

  1. La pagina padre e la pagina iframe provengono da domini diversi.
  2. Stanno usando diversi protocolli, uno è su http: // e altro è su https: //.

Qualsiasi soluzione a questa restrizione sarebbe estremamente insicuro.

Ad esempio, immagina di aver registrato il dominio superwinningcontest.com e di aver inviato link alle e-mail delle persone. Quando caricavano la pagina principale, potevo hide alcuni iframe s lì e leggere il loro feed di Facebook, controllare le recenti transazioni Amazon o PayPal, o – se hanno usato un servizio che non implementava una sicurezza sufficiente – trasferire denaro da i loro account. Ecco perché JavaScript è limitato allo stesso dominio e allo stesso protocollo.

Nell’IFRAME, rendi pubblica la tua funzione sull’object della finestra:

 window.myFunction = function(args) { doStuff(); } 

Per l’accesso dalla pagina principale, utilizzare questo:

 var iframe = document.getElementById("iframeId"); iframe.contentWindow.myFunction(args); 

Se iFrame e il documento che lo contiene si trovano su un dominio diverso, i metodi precedentemente pubblicati potrebbero non funzionare, ma esiste una soluzione:

Ad esempio, se il documento A contiene un elemento iframe che contiene il documento B e lo script nel documento A chiama postMessage () sull’object Window del documento B, quindi verrà generato un evento messaggio su quell’object, contrassegnato come proveniente dalla finestra di documento A. Lo script nel documento A potrebbe essere simile a:

 var o = document.getElementsByTagName('iframe')[0]; o.contentWindow.postMessage('Hello world', 'http://b.example.org/'); 

Per registrare un gestore di eventi per eventi in entrata, lo script utilizza addEventListener () (o meccanismi simili). Ad esempio, lo script nel documento B potrebbe essere simile a:

 window.addEventListener('message', receiver, false); function receiver(e) { if (e.origin == 'http://example.com') { if (e.data == 'Hello world') { e.source.postMessage('Hello', e.origin); } else { alert(e.data); } } } 

Questo script controlla innanzitutto che il dominio sia il dominio previsto, quindi esamina il messaggio, che viene visualizzato all’utente o che risponde inviando un messaggio al documento che ha inviato il messaggio in primo luogo.

tramite http://dev.w3.org/html5/postmsg/#web-messaging

Solo per la cronaca, oggi mi sono imbattuto nello stesso problema ma questa volta la pagina è stata incorporata in un object, non in un iframe (poiché si trattava di un documento XHTML 1.1). Ecco come funziona con gli oggetti:

 document .getElementById('targetFrame') .contentDocument .defaultView .targetFunction(); 

(scusa per le brutte interruzioni di riga, non si adattava a una singola riga)

L’IFRAME dovrebbe essere nella collezione frames[] . Usa qualcosa come

 frames['iframeid'].method(); 

Quirksmode aveva un post su questo .

Poiché la pagina è ora rotta e accessibile solo tramite archive.org, l’ho riprodotta qui:

IFrame

In questa pagina fornisco una breve panoramica sull’accesso agli iframe dalla pagina in cui si trovano. Non sorprende che ci siano alcune considerazioni sul browser.

Un iframe è un frame inline, un frame che, pur contenendo una pagina completamente separata con il proprio URL, è comunque posizionato all’interno di un’altra pagina HTML. Questo offre possibilità molto interessanti nel web design. Il problema è accedere all’iframe, ad esempio per caricare una nuova pagina al suo interno. Questa pagina spiega come farlo.

Cornice o object?

La domanda fondamentale è se l’iframe è visto come una cornice o come un object.

  • Come spiegato nelle pagine Introduzione alle cornici , se si utilizzano i frame, il browser crea per te una gerarchia di frame ( top.frames[1].frames[2] e simili). L’iframe si inserisce in questa gerarchia di frame?
  • O il browser vede un iframe come solo un altro object, un object che ha una proprietà src? In tal caso dobbiamo usare una chiamata DOM standard (come document.getElementById('theiframe')) per accedervi. In generale i browser consentono entrambe le viste su iframe “reali” (codificati), ma gli iframe generati non sono accessibili come frame.

Attributo NAME

La regola più importante è dare a qualsiasi iframe un attributo name , anche se usi anche un id .

  

La maggior parte dei browser richiede l’attributo name per creare la parte iframe della gerarchia dei frame. Alcuni browser (in particolare Mozilla) richiedono l’ id per rendere l’iframe accessibile come object. Assegnando entrambi gli attributi all’iframe, mantieni le tue opzioni aperte. Ma il name è molto più importante di id .

Accesso

O accedete all’iframe come a un object e modificate il suo src o accedete all’iframe come a una cornice e modificate la sua location.href .

document.getElementById (‘iframe_id’). src = ‘newpage.html’; frames [‘iframe_name’]. location.href = ‘newpage.html’; La syntax del frame è leggermente preferibile perché Opera 6 lo supporta ma non la syntax dell’object.

Accesso all’iframe

Quindi per un’esperienza completa del cross-browser dovresti dare un nome all’iframe e usare il

 frames['testiframe'].location.href 

syntax. Per quanto ne so, questo funziona sempre.

Accedere al documento

L’accesso al documento all’interno dell’iframe è abbastanza semplice, purché si usi l’attributo name . Per contare il numero di link nel documento frames['testiframe'].document.links.length , fai frames['testiframe'].document.links.length .

Iframe generati

Quando si genera un iframe attraverso il DOM W3C, l’iframe non viene immesso immediatamente nell’array dei frames , tuttavia, e la syntax frames['testiframe'].location.href syntax frames['testiframe'].location.href non funzionerà immediatamente. Il browser richiede un po ‘di tempo prima che l’iframe compaia nell’array, tempo durante il quale non può essere eseguito alcuno script.

document.getElementById('testiframe').src syntax document.getElementById('testiframe').src funziona bene in tutte le circostanze.

L’attributo target di un collegamento non funziona con iframe generati, tranne in Opera, anche se ho dato al mio iframe generato sia un name che un id .

La mancanza di supporto di target significa che è necessario utilizzare JavaScript per modificare il contenuto di un iframe generato, ma dal momento che è necessario comunque JavaScript per generarlo, non lo vedo come un grosso problema.

Dimensione del testo in iframe

Un baco curioso solo per Explorer 6:

Quando si modifica la dimensione del testo tramite il menu Visualizza, le dimensioni del testo negli iframe vengono modificate correttamente. Tuttavia, questo browser non modifica le interruzioni di riga nel testo originale, in modo che parte del testo possa diventare invisibile o che si verifichino interruzioni di riga mentre la riga potrebbe contenere un’altra parola.

Ho trovato una soluzione piuttosto elegante.

Come hai detto, è abbastanza facile eseguire il codice che si trova sul documento principale. E questa è la base del mio codice, fare esattamente l’opposto.

Quando viene caricato il mio iframe, chiamo una funzione situata sul documento genitore, passando come argomento un riferimento a una funzione locale, che si trova nel documento dell’iframe. Il documento principale ora ha un accesso diretto alla funzione dell’iframe attraverso questo riferimento.

Esempio:

Sul genitore:

 function tunnel(fn) { fn(); } 

Sull’iframe:

 var myFunction = function() { alert("This work!"); } parent.tunnel(myFunction); 

Quando carica l’iframe, chiamerà parent.tunnel (YourFunctionReference), che eseguirà la funzione ricevuta nel parametro.

È semplice, senza dover affrontare tutti i metodi non standardizzati dai vari browser.

Alcune di queste risposte non risolvono il problema CORS, o non rendono ovvio dove posizioni i frammenti di codice per rendere ansible la comunicazione.

Ecco un esempio concreto. Diciamo che voglio fare clic su un pulsante nella pagina padre e fare qualcosa all’interno dell’iframe. Ecco come lo farei.

parent_frame.html

  function call_button_inside_frame() { document.getElementById('my_iframe').contentWindow.postMessage('foo','*'); } 

iframe_page.html

 window.addEventListener("message", receiveMessage, false); function receiveMessage(event) { if(event) { click_button_inside_frame(); } } function click_button_inside_frame() { document.getElementById('frame_button').click(); } 

Per andare nella direzione opposta (fai clic sul pulsante all’interno di iframe per chiamare il metodo al di fuori di iframe) passa semplicemente a dove è in esecuzione lo snippet di codice e modifica questo:

 document.getElementById('my_iframe').contentWindow.postMessage('foo','*'); 

a questa:

 window.parent.postMessage('foo','*') 

Continuando con la risposta di JoelAnair :

Per maggiore robustezza, utilizzare come segue:

 var el = document.getElementById('targetFrame'); if(el.contentWindow) { el.contentWindow.targetFunction(); } else if(el.contentDocument) { el.contentDocument.targetFunction(); } 

Workd like charm 🙂

Alla base della risposta di Nitin Bansal

e per ancora più robustezza:

 function getIframeWindow(iframe_object) { var doc; if (iframe_object.contentWindow) { return iframe_object.contentWindow; } if (iframe_object.window) { return iframe_object.window; } if (!doc && iframe_object.contentDocument) { doc = iframe_object.contentDocument; } if (!doc && iframe_object.document) { doc = iframe_object.document; } if (doc && doc.defaultView) { return doc.defaultView; } if (doc && doc.parentWindow) { return doc.parentWindow; } return undefined; } 

e

 ... var el = document.getElementById('targetFrame'); getIframeWindow(el).targetFunction(); ... 
  $("#myframe").load(function() { alert("loaded"); }); 

Stesse cose, ma un modo un po ‘più semplice sarà come aggiornare la pagina padre dalla pagina all’interno di iframe . Basta chiamare la funzione della pagina madre per triggersre la funzione javascript per ricaricare la pagina:

 window.location.reload(); 

O fallo direttamente dalla pagina in iframe:

 window.parent.location.reload(); 

Entrambe le opere.

Se vogliamo chiamiamo la funzione javascript della pagina madre dall’iframe generato dalla codifica. ex shadowbox o lightbox

window.parent.targetFunction ();

Prova solo parent.myfunction()

Usare seguendo per chiamare la funzione di un frame nella pagina padre

 parent.document.getElementById('frameid').contentWindow.somefunction()