Richiamo del codice JavaScript in un iframe dalla pagina principale


615

Fondamentalmente, ho un iframeincorporato in una pagina e iframeha alcune routine JavaScript che devo richiamare dalla pagina principale.

Ora il contrario è abbastanza semplice come devi solo chiamare parent.functionName(), ma sfortunatamente ho bisogno esattamente del contrario.

Si noti che il mio problema non sta modificando l' URL di origine di iframe, ma invocando una funzione definita in iframe.


42
La tua nota su parent.fuctioName () ha risolto il mio problema di chiamare una funzione nel codice HTML dell'iframe. Grazie!
CyberFonic,

1
Nota quando esegui il debug puoi fare cose come window.location.href o parent.location.href per visualizzare l'URL dell'iframe, se vuoi verificare di avere un riferimento all'iframe che stai cercando.
AaronLS

Vedi la risposta di @le dorfier ... ha funzionato perfettamente per me.
ErickBest,

Risposte:


542

Supponiamo 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.framesinvece di document.getElementById.

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

3
funziona in FF 7, Chrome 12, IE 8/9 e Safari (non sono sicuro di questa versione)
Darcy

3
Questa soluzione non funziona per il mio gadget, ecco il mio codice document.getElementById('remote_iframe_0').contentWindow.my.create_element_gadg‌​et('verify_user');"remote_iframe_0 viene creato a livello di programmazione da un server shindig apache ma window.parent.document.getElementById('remote_iframe_0').contentWindow.my.create_element_gadg‌​et('verify_user');"funziona
J Bourne,

3
@Dirty Henry cosa intendi con "una funzione jQuery?" jQuery è una libreria JavaScript.
Joel Anair,

8
@JellicleCat Questo perché la pagina padre e l'iframe hanno host diversi, rendendolo un frame di origine incrociata, come ti dice il messaggio. Finché il protocollo, il dominio e la porta della pagina principale e iframe corrispondono, tutto funzionerà perfettamente.
Mark Amery,

1
Ho aggiunto un esempio su come utilizzare il metodo window.frames menzionato.
Elijah Lynn,

145

Ci sono alcune stranezze di cui essere consapevoli qui.

  1. HTMLIFrameElement.contentWindowè probabilmente il modo più semplice, ma non è proprio una proprietà standard e alcuni browser non lo supportano, soprattutto quelli più vecchi. Questo perché lo standard HTML DOM livello 1 non ha nulla da dire windowsull'oggetto.

  2. Puoi anche provare HTMLIFrameElement.contentDocument.defaultView, cosa che consente un paio di browser meno recenti, ma IE no. Anche così, lo standard non dice esplicitamente di recuperare l' windowoggetto, per lo stesso motivo di (1), ma puoi prendere qui alcune versioni di browser extra se ti interessa.

  3. window.frames['name']restituire la finestra è l'interfaccia più vecchia e quindi più affidabile. Ma devi quindi usare un name="..."attributo per essere in grado di 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 cavartela ad es. se sai di avere solo un iframe nella pagina.

  5. È del tutto possibile che l'iframe figlio non sia ancora stato caricato, o qualcos'altro è andato storto per renderlo inaccessibile. Potresti trovare più semplice invertire il flusso delle comunicazioni: vale a dire, l'iframe figlio notifica il proprio window.parentscript al termine del caricamento ed è pronto per essere richiamato. Passando uno dei propri oggetti (ad es. Una funzione di callback) allo script parent, quel genitore può quindi comunicare direttamente con lo script nell'iframe senza doversi preoccupare di quale HTMLIFrameElement è associato.


13
Roba fantastica! Soprattutto il tuo suggerimento 5. ha dimostrato di essere estremamente prezioso. Mi ha risolto un sacco di mal di testa quando provavo ad accedere alle funzioni iFrame dal genitore in Chrome. Passare l'oggetto funzione dall'iFrame lo ha fatto funzionare come un fascino in Chrome, FF e persino IE da 9 a 7 e ha anche reso molto facile controllare se la funzione era già stata caricata. Grazie!
Jpsy,

Il numero 3 funziona, ma meglio se lo fai come @le dorfier inseriscilo nel suo commento. Notare la methode()parte.
ErickBest,

Si noti inoltre che a causa delle restrizioni di sicurezza nei browser moderni (testato FF29 e Chrome34) è molto importante il luogo in cui si effettua la chiamata di funzione. Il semplice richiamo della funzione da un tag di script o $ (document) .ready () non funzionerà. Invece mettere la chiamata all'interno del tag onload del corpo, o in un <a ancoraggio href="javascript:doit();"> farlo </a> come suggerito elswhere (vedi stackoverflow.com/questions/921387/... ). Anche il passaggio della chiamata di funzione a uno script come callback di solito funziona.
Titusn,

@chovy: No, vedi i chiarimenti nella risposta di Vivek al riguardo.
bobince,

66

È possibile richiamare una funzione JS genitore da iframe, ma solo quando sia il genitore che la pagina caricata nel iframesono dallo stesso dominio, ovvero abc.com, ed entrambi utilizzano lo stesso protocollo, ovvero entrambi sono attivi http://o https://.

La chiamata fallirà nei seguenti casi:

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

Qualsiasi soluzione alternativa a questa restrizione sarebbe estremamente insicura.

Ad esempio, immagina di aver registrato il dominio superwinningcontest.com e di aver inviato collegamenti alle e-mail delle persone. Quando hanno caricato la pagina principale, ho potuto nascondere qualche iframes lì dentro e leggere il loro feed di Facebook, controllare le recenti transazioni Amazon o PayPal o, se hanno utilizzato un servizio che non implementava una sicurezza sufficiente, trasferire denaro dal loro conti. Ecco perché JavaScript è limitato allo stesso dominio e allo stesso protocollo.


6
La soluzione è quella di utilizzare il bellissimo e pericoloso en.wikipedia.org/wiki/Cross-document_messaging
Laramie

Qualcuno sa se un sottodominio diverso provocherà un errore? Sto riscontrando difficoltà nel debug di un problema che credo sia correlato a questo: l'iframe sta chiamando una funzione della finestra padre, ma la chiamata non sta avvenendo.
Jake,

1
Nota, fallirebbe anche per numeri di porta diversi. cioè abc.com:80! = abc.com:8080
prasanthv il

31

Nell'IFRAME, rendi pubblica la tua funzione sull'oggetto window:

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

Per accedere dalla pagina principale, utilizzare questo:

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

Bella risposta. Non sono sicuro della convenzione qui. Ho una domanda di follow-up. Se dovessi iniziare una nuova domanda, lo farò. Ho un problema L'iframe della mia pagina viene popolato dinamicamente. Contiene un pulsante il cui onclick()evento chiama semplicemente window.print(). Questo stampa il contenuto del iframeperfettamente. Ma quando la funzione pubblica della pagina iframe chiama window.print()e se la pagina padre chiama la funzione pubblica, viene stampato il contenuto del genitore. Come devo codificare questo in modo che la chiamata a window.print()nella funzione pubblica si comporti come onclicknell'evento?
Karl

1
@Karl Non vuoi chiamare onclick. Vuoi chiamare iframe.contentWindow.print().
Tomalak,

Sfortunatamente, ciò non funziona. Forse dovrei iniziare una nuova domanda e documentare il mio codice? In entrambi i casi, viene stampato anche il contenuto della pagina principale. document.getElementById('myFrame').contentWindow.print();' and the pubic function printContent () `(non il gestore dell'evento oncick) che chiama è window.print()stato chiamato in questo modo:document.getElementById('myFrame').contentWindow.printContent();
Karl

1
@Karl - Sì, allora è meglio iniziare una nuova domanda. A meno che la finestra principale non si trovi su un dominio diverso dall'iframe. Quindi niente di ciò che proverai funzionerà mai .
Tomalak,

Quello che ho riportato qui sembra essere un problema di IE (test in IE8). Nessun problema nella versione corrente di Chrome. Devo ancora testare altri browser comunque. Per coloro che sono interessati, vedi questo jsFiddle (penso che questo sia un buon esempio di caricamento iframe dinamico e di chiamata a una funzione pubblica da parte del genitore.)
Karl

20

Se la destinazione dell'iFrame e il documento contenente 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'oggetto Window del documento B, allora verrà generato un evento messaggio sull'oggetto, contrassegnato come originario dalla finestra di documento A. Lo script nel documento A potrebbe apparire come:

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

Per registrare un gestore eventi per gli eventi in arrivo, lo script userebbe addEventListener () (o meccanismi simili). Ad esempio, lo script nel documento B potrebbe apparire come:

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 verifica innanzitutto che il dominio sia il dominio previsto, quindi esamina il messaggio, che viene visualizzato all'utente o risponde inviando un messaggio al documento che ha inviato il messaggio in primo luogo.

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


1
easyXDM fornisce un'astrazione su PostMessage per i browser più vecchi (incluso un fallback Flash (LocalConnection) per i dinosauri testardi).
JonnyReveves

1
è fantastico ... dopo aver provato sopra le risposte finalmente ho ricevuto la tua risposta, grazie!
vkGunasekaran

9

Solo per la cronaca, ho riscontrato lo stesso problema oggi, ma questa volta la pagina è stata incorporata in un oggetto, non in un iframe (poiché era 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 rientrava in una sola riga)


8

L'IFRAME dovrebbe essere nella frames[]raccolta. Usa qualcosa di simile

frames['iframeid'].method();

Questa risposta potrebbe certamente utilizzare qualche informazione in più, dato che ci sono sicuramente altre considerazioni. Per uno, presumo che lo sviluppatore debba creare methoduna proprietà windowdell'oggetto iframe .
matty

8

Quirksmode ha pubblicato 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 dell'accesso agli iframe dalla pagina in cui si trovano. Non sorprende, ci sono alcune considerazioni sul browser.

Un iframe è un frame inline, un frame che, pur contenendo una pagina completamente separata con il proprio URL, viene comunque inserito in un'altra pagina HTML. Questo offre ottime possibilità 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 oggetto?

La domanda fondamentale è se l'iframe è visto come una cornice o come un oggetto.

  • Come spiegato nelle pagine Introduzione ai frame , se si utilizzano i frame il browser crea una gerarchia di frame per l'utente ( top.frames[1].frames[2]e simili). L'iframe si adatta a questa gerarchia di frame?
  • Oppure il browser vede un iframe come un altro oggetto, un oggetto 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 visualizzazioni su iframe "reali" (codificati), ma gli iframe generati non sono accessibili come frame.

Attributo NAME

La regola più importante è dare qualsiasi iframe che crei un nameattributo, anche se usi anche un id.

<iframe src="iframe_page1.html"
    id="testiframe"
    name="testiframe"></iframe>

La maggior parte dei browser necessita namedell'attributo per rendere l'iframe parte della gerarchia dei frame. Alcuni browser (in particolare Mozilla) hanno bisogno iddi rendere accessibile l'iframe come oggetto. Assegnando entrambi gli attributi all'iframe tieni aperte le tue opzioni. Ma nameè molto più importante di id.

Accesso

O accedete all'iframe come oggetto e lo modificate srcoppure accedete all'iframe come cornice e cambiate il suo location.href.

document.getElementById ('iframe_id'). src = 'newpage.html'; frames ['iframe_name']. location.href = 'newpage.html'; La sintassi della cornice è leggermente preferibile perché Opera 6 la supporta ma non la sintassi dell'oggetto.

Accesso all'iframe

Quindi, per un'esperienza completa tra browser, dovresti dare un nome all'iframe e usare il

frames['testiframe'].location.href

sintassi. Per quanto ne so, funziona sempre.

Accesso al documento

L'accesso al documento all'interno dell'iframe è abbastanza semplice, a condizione che tu utilizzi l' nameattributo. Per contare il numero di collegamenti nel documento nell'iframe, fare frames['testiframe'].document.links.length.

Iframe generati

Quando si genera un iframe tramite il DOM W3C, iframe non viene immediatamente immesso framesnell'array eframes['testiframe'].location.href sintassi 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.

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

L' targetattributo di un collegamento non funziona neanche con iframe generati, tranne in Opera, anche se ho dato al mio iframe generato sia a nameche aid .

La mancanza di target supporto significa che è necessario utilizzare JavaScript per modificare il contenuto di un iframe generato, ma poiché è necessario JavaScript in ogni caso per generarlo in primo luogo, non vedo questo problema.

Dimensione del testo in iframe

Un curioso bug di Explorer 6:

Quando si modificano le dimensioni 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, pertanto una parte del testo potrebbe diventare invisibile oppure potrebbero verificarsi interruzioni di riga mentre la riga potrebbe contenere ancora un'altra parola.


5
Quel collegamento sembra essere rotto.
zaphod,

1
E a peggiorare le cose, non riesco a trovare la pagina correlata da nessuna parte su quirksmode.
Stricjux,


7

Ho trovato una soluzione abbastanza elegante.

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

Quando viene caricato il mio iframe, chiamo una funzione che si trova sul documento principale, passando come argomento un riferimento a una funzione locale, situata 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 l'iframe viene caricato, chiamerà parent.tunnel (YourFunctionReference), che eseguirà la funzione ricevuta nel parametro.

Che semplice, senza dover affrontare tutti i metodi non standard dei vari browser.


Ciao, puoi confermare questo "Che semplice, senza dover affrontare tutti i metodi non standard dei vari browser."?
Milche Patern,

1
Uso questo metodo su vari progetti, sembra funzionare molto bene. Non ho testato personalmente tutti i browser in circolazione, ma non ho mai ricevuto nemmeno una segnalazione di bug.
Julien L,

Funziona come un fascino, IE 11, Chrome ~ 50.
Augustas

1
Immagino che non sia interdominio. Lo è?
Tushar Shukla,

@TusharShukla Purtroppo no, non lo è.
jeff-h,

6

Alcune di queste risposte non risolvono il problema CORS o non rendono ovvio dove si posizionano gli snippet di codice per rendere possibile la comunicazione.

Ecco un esempio concreto. Di 'che voglio fare clic su un pulsante nella pagina principale e fare in modo che qualcosa faccia all'interno dell'iframe. Ecco come lo farei.

parent_frame.html

<button id='parent_page_button' onclick='call_button_inside_frame()'></button>

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 nell'altra direzione (fare clic sul pulsante all'interno di iframe per chiamare il metodo all'esterno di iframe) basta cambiare la posizione dello snippet di codice e modificarlo:

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

a questo:

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

4

Continuando con la risposta di JoelAnair :

Per una maggiore robustezza, utilizzare come segue:

var el = document.getElementById('targetFrame');

if(el.contentWindow)
{
   el.contentWindow.targetFunction();
}
else if(el.contentDocument)
{
   el.contentDocument.targetFunction();
}

Funzionava come un incanto :)


3

Seguendo la risposta di Nitin Bansal

e per una resistenza ancora maggiore:

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

var frame_win = getIframeWindow(el);

if (frame_win) {
  frame_win.targetFunction();
  ...
}
...




1

Se si desidera richiamare la funzione JavaScript sul genitore dall'iframe generato da un'altra funzione ex shadowbox o lightbox.

Dovresti provare a usare l' windowoggetto e invocare la funzione genitore:

window.parent.targetFunction();

Credo che l'OP stia cercando di andare nella direzione
opposta

-3

Usare il seguente per chiamare la funzione di un frame nella pagina principale

parent.document.getElementById('frameid').contentWindow.somefunction()
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.