Chiamare una funzione della finestra padre da un iframe


282

Voglio chiamare una funzione JavaScript della finestra principale da un iframe.

<script>
    function abc()
    {
        alert("sss");
    }
</script>

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>

1
Non posso mostrare nulla in questo momento (2016), non so se il vecchio pergolato sosterrebbe alcuno
Weijing Jay Lin

Risposte:


438
<a onclick="parent.abc();" href="#" >Call Me </a>

Vedi window.parent

Restituisce un riferimento al genitore della finestra o del sottotelaio correnti.

Se una finestra non ha un genitore, la sua proprietà genitore è un riferimento a se stessa.

Quando una finestra viene caricato in una <iframe>, <object>o <frame>, il suo genitore è la finestra con l'elemento incorporamento finestra.


17
Tenere sempre presente che il documento principale e il documento iframe devono corrispondere per protocollo e nome dominio. Se ciò non accade, verrà visualizzato un errore di sicurezza in quanto non è consentito avere script tra domini.
a4bike,

M mi chiedo solo quale delle due alertverrà invocata; la alertfunzione parent o iframe alert, nel caso in cui parent.abc();viene chiamato iframe?
Prakhar Mishra

@PrakharMishra Non essere confuso. genitore significa genitore.
Sahu V Kumar,

3
@ a4bike per tali scenari, window.postMessage()(o window.parent.postMessage()) esiste. Controlla la risposta di @Andrii
Fr0zenFyr

81

Di recente ho dovuto scoprire perché anche questo non ha funzionato.

Il javascript che vuoi chiamare dall'iframe figlio deve essere nella testa del genitore. Se è nel corpo, lo script non è disponibile nell'ambito globale.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="parent.abc();" href="#">Click Me</a>
    </iframe>
</body>

Spero che questo aiuti chiunque si imbatte nuovamente in questo problema.


1
Nessuna delle tecniche menzionate in questo post funziona su Chrome. Qualche soluzione per questo?
Kumar Kush,

3
Se ricordo bene, non riuscivo a farlo funzionare come previsto se l'iframe avesse un dominio diverso dal genitore. Spiacenti, questa non è una soluzione, ma potrebbe spiegare perché non funziona.
Ash Clarke,

1
Sì. So che è a causa di domini diversi, ma non c'è un modo per aggirare il problema?
Kumar Kush,

1
Ho appena pubblicato quello che potrebbe essere una soluzione alternativa al tuo problema. Dai un'occhiata all'altra risposta.
Ash Clarke,

1
Secondo le stesse regole di determinazione della politica di origine (vedi: en.wikipedia.org/wiki/… ), i sottodomini sono considerati un nome host diverso da un sottodominio di un dominio. Se non l'hai già fatto, puoi provare a impostare document.domain sul sottodominio?
Ash Clarke,

73

Window.postMessage ()

Questo metodo consente la cross-origincomunicazione in sicurezza .

E se si ha accesso al codice della pagina padre, è possibile chiamare qualsiasi metodo padre e tutti i dati da cui è possibile passare direttamente Iframe. Ecco un piccolo esempio:

Pagina principale:

if (window.addEventListener) {
    window.addEventListener("message", onMessage, false);        
} 
else if (window.attachEvent) {
    window.attachEvent("onmessage", onMessage, false);
}

function onMessage(event) {
    // Check sender origin to be trusted
    if (event.origin !== "http://example.com") return;

    var data = event.data;

    if (typeof(window[data.func]) == "function") {
        window[data.func].call(null, data.message);
    }
}

// Function to be called from iframe
function parentFunc(message) {
    alert(message);
}

Codice Iframe:

window.parent.postMessage({
    'func': 'parentFunc',
    'message': 'Message text from iframe.'
}, "*");
// Use target origin instead of *

AGGIORNAMENTI:

Nota sulla sicurezza:

Fornire sempre un targetOrigin specifico, NON *, se si sa dove dovrebbe trovarsi il documento dell'altra finestra. Non fornire un target specifico rivela i dati inviati a qualsiasi sito dannoso interessato (commento di ZalemCitizen ).

Riferimenti:


1
Preferisco usarlo su altri. Soprattutto perché ha più senso usare iframe su documenti di origine incrociata (sebbene i programmatori sfruttino iframe il più delle volte) e dato l'ampio supporto per questa funzione sui browser.
Fr0zenFir

1
Grazie! Devo sempre passare un'ora o più a tornare indietro e cercare come gestire i messaggi con esempi complicati e dettagliati. Questo ha funzionato in 60 secondi. Grazie per un esempio conciso e puntuale.
Randall, al

2
vale la pena sollevarlo (dai documenti Web di MDN ): fornire sempre un targetOrigin specifico, non *, se si sa dove dovrebbe trovarsi il documento dell'altra finestra. Non fornire un target specifico rivela i dati inviati a qualsiasi sito dannoso interessato
ZalemCitizen

20

Ho pubblicato questo come una risposta separata in quanto non è correlata alla mia risposta esistente.

Questo problema è stato recentemente ripreso per accedere a un genitore da un iframe che fa riferimento a un sottodominio e le correzioni esistenti non hanno funzionato.

Questa volta la risposta è stata quella di modificare document.domain della pagina padre e iframe in modo che fossero gli stessi. Ciò ingannerà gli stessi controlli di politica di origine nel pensare che coesistano esattamente nello stesso dominio (i sottodomini sono considerati un host diverso e non superano lo stesso controllo di politica di origine).

Inserisci quanto segue in <head>della pagina nell'iframe in modo che corrisponda al dominio principale (modifica per il tuo tipo di documento).

<script>
    document.domain = "mydomain.com";
</script>

Si noti che ciò genererà un errore nello sviluppo di localhost, quindi utilizzare un segno di spunta come il seguente per evitare l'errore:

if (!window.location.href.match(/localhost/gi)) {
    document.domain = "mydomain.com";
} 

e che ne dici di provare questo in localhost? qualche soluzione alternativa per quello?
Umesh Awasthi,

Vedi: "Nota che questo genererà un errore nello sviluppo di localhost, quindi usa un segno di spunta come il seguente per evitare l'errore"
Ash Clarke,

2
Vale la pena notare che (almeno in Google Chrome) entrambi, padre e figlio DEVONO IMPOSTARE document.domain anche se uno di essi è già "corretto"! Esempio: Parent è example.comiframe abc.example.com, quindi sia parent che iframe devono chiamaredocument.domain = "example.com"
KillerX

Sì, è corretto, ho fatto un refuso qui: "la pagina nell'iframe è la stessa". dovrebbe essere "page e iframe essere uguali". ..... Grazie!
Ash Clarke,

per if () perché non dovresti usare if (document.domain! = "mydomain.com"? Inoltre, sono confuso, <script> va nella finestra principale o in iFrame? Inoltre, impostando il document.domain in iFrame genera "Impossibile impostare la proprietà 'domain' su 'Document': 'localhost' non è un suffisso di 'sc-localhost'.
user2568374

18

Puoi usare

window.top

vedi quanto segue.

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="window.top.abc();" href="#">Click Me</a>
    </iframe>
</body>

Quando si tenta di chiamare parent.custom_function (); da un iframe non funziona potresti trovare window.top.custom_function (); funzionerà. Funziona per me per qualche strana ragione. I miei javascript nella finestra principale sono tutti incorporati nel piè di pagina, ho letto da qualche parte che l'inclusione dei file javascript nel piè di pagina causa il problema parent.custom_function () non funziona.
Friso Horstman,

@Vinothkumar, una domanda per favore, qual è la differenza tra la chiamata di "window.top.abc ()" che la chiamata di solo "abc ()", grazie in anticipo =)
Zilev av

@Zilev av L'intero punto di questo thread sta chiamando una funzione in un documento padre da un iframe figlio. Questa è la differenza La chiamata abc()funzionerebbe solo se function abc()fosse stata dichiarata nell'iframe invece che nella pagina padre. window.top.abc()esce dall'iframe nel documento principale.
Sean Kendle,

3

Un'altra aggiunta per chi ne ha bisogno. La soluzione di Ash Clarke non funziona se usano protocolli diversi, quindi assicurati che se stai usando SSL, anche il tuo iframe sta usando SSL o interromperà la funzione. La sua soluzione ha funzionato per i domini stessi, quindi grazie per quello.


2

La soluzione fornita da Ash Clarke per i sottodomini funziona alla grande, ma tieni presente che devi includere document.domain = "mydomain.com"; sia nell'intestazione della pagina iframe che nell'intestazione della pagina padre, come indicato nel link stesso controllo della politica di origine

Un'estensione importante della stessa politica di origine implementata per l'accesso al DOM JavaScript (ma non per la maggior parte degli altri tipi di controlli della stessa origine) è che due siti che condividono un dominio di primo livello comune possono scegliere di comunicare nonostante non riesca lo "stesso host" controllare impostando reciprocamente la rispettiva proprietà DOM document.domain sullo stesso frammento qualificato e destro del nome host corrente. Ad esempio, se http://en.example.com/ e http://fr.example.com/ impostano entrambi document.domain su "example.com", sarebbero da quel punto considerati la stessa origine per scopo della manipolazione del DOM.


Sì, è corretto, ho fatto un refuso qui: "la pagina nell'iframe è la stessa". dovrebbe essere "page e iframe essere uguali". ..... Grazie!
Ash Clarke,

che ne dici di eseguire file nel computer locale? qual è il valore di document.domain?
Raptor il

Sarà localhosto l'indirizzo IP della macchina (in genere 127.0.0.1), a seconda di ciò che si trova nella barra degli indirizzi URL.
Ash Clarke,

2

parent.abc () funzionerà sullo stesso dominio solo per motivi di sicurezza. ho provato questa soluzione alternativa e il mio ha funzionato perfettamente.

<head>
    <script>
    function abc() {
        alert("sss");
    }

    // window of the iframe
    var innerWindow = document.getElementById('myFrame').contentWindow;
    innerWindow.abc= abc;

    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="abc();" href="#">Click Me</a>
    </iframe>
</body>

Spero che questo ti aiuti. :)


Questo è anche solo un uso per il documento di iframe, aggiungendo enormi complicazioni se è necessario fare riferimento ai controlli nel modulo padre.
Paul,

1

Con Firefox e Chrome puoi usare:

<a href="whatever" target="_parent" onclick="myfunction()">

Se myFunzione è presente sia in iframe che in parent, verrà chiamato quello parent.



Come affermato da Ash Clarke, il javascript che si desidera chiamare dall'iframe figlio deve essere in testa al genitore.
fiocco di neve

La risposta accettata non ha bisogno che lo script sia in testa. Non ho verificato se anche questa soluzione non ha più bisogno che lo script sia in testa o meno.
Guy Schalnat,

0

Mentre alcune di queste soluzioni potrebbero funzionare, nessuna di esse segue le migliori pratiche. Molti assegnano variabili globali e potresti trovarti a effettuare chiamate a più variabili o funzioni padre, portando a uno spazio dei nomi disordinato e vulnerabile.

Per evitare ciò, utilizzare un modello di modulo. Nella finestra principale:

var myThing = {
    var i = 0;
    myFunction : function () {
        // do something
    }
};

var newThing = Object.create(myThing);

Quindi, nell'iframe:

function myIframeFunction () {
    parent.myThing.myFunction();
    alert(parent.myThing.i);
};

Questo è simile ai modelli descritti nel capitolo Ereditarietà del testo fondamentale di Crockford, "Javascript: le parti buone". Puoi anche saperne di più sulla pagina di w3 per le migliori pratiche di Javascript. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

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.