Llamar a una función de ventana principal desde un iframe

281

Quiero llamar a una función JavaScript de ventana principal desde un iframe.

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

<iframe id="myFrame">
    <a onclick="abc();" href="#">Call Me</a>
</iframe>
Arjun Singh
fuente
1
No podré mostrar nada en este momento (2016), no sé si la glorieta mayor apoyaría algo
Weijing Jay Lin

Respuestas:

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

Ver window.parent

Devuelve una referencia al padre de la ventana o subtrama actual.

Si una ventana no tiene un elemento primario, su propiedad principal es una referencia a sí misma.

Cuando una ventana se carga en una <iframe>, <object>o <frame>, su padre es la ventana con el elemento de la incorporación de la ventana.

rahul
fuente
17
Siempre tenga en cuenta que el documento padre y el documento iframe deben coincidir por protocolo y nombre de dominio. Si no sucede, obtendrá un error de seguridad, ya que no se permite tener secuencias de comandos de dominio cruzado.
a4bike
M solo se pregunta cuál de los dos alertse invocará; alertfunción del padre o la alertfunción del iframe , en caso de que parent.abc();se llame en el iframe?
Prakhar Mishra
@PrakharMishra No se confunda. padre significa padre.
Sahu V Kumar
3
@ a4bike para tales escenarios, window.postMessage()(o window.parent.postMessage()) existe. Compruebe la respuesta de @Andrii
Fr0zenFyr
81

Recientemente tuve que descubrir por qué esto no funcionó también.

El javascript al que desea llamar desde el iframe secundario debe estar en la cabeza del padre. Si está en el cuerpo, el script no está disponible en el ámbito global.

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

Espero que esto ayude a cualquiera que se encuentre con este problema nuevamente.

Ash Clarke
fuente
1
Ninguna de las técnicas mencionadas en esta publicación funciona en Chrome. ¿Alguna solución para esto?
Kumar Kush el
3
Si recuerdo correctamente, no podría hacer que esto funcione como se esperaba si el iframe tuviera un dominio diferente al padre. Lo sentimos, esta no es una solución, pero podría explicar por qué no funciona.
Ash Clarke
1
Si. Sé que se debe a diferentes dominios, pero ¿no hay una manera de solucionar esto?
Kumar Kush el
1
Acabo de publicar lo que podría ser una solución a su problema. Echa un vistazo a la otra respuesta.
Ash Clarke
1
Según las mismas reglas de determinación de políticas de origen (ver: en.wikipedia.org/wiki/… ), los subdominios se consideran un nombre de host diferente a un subdominio de un dominio. Si aún no lo ha hecho, ¿podría intentar establecer document.domain en el subdominio?
Ash Clarke
72

Window.postMessage ()

Este método permite la cross-origincomunicación de forma segura .

Y si tiene acceso al código de la página principal, se puede llamar a cualquier método principal y también se puede pasar cualquier información directamente Iframe. Aquí hay un pequeño ejemplo:

Página principal:

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

Código de iframe:

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

ACTUALIZACIONES:

Nota de seguridad:

Proporcione siempre un TargetOrigin específico, NO *, si sabe dónde debe ubicarse el documento de la otra ventana. Si no se proporciona un objetivo específico, se divulgan los datos que envía a cualquier sitio malicioso interesado (comentario de ZalemCitizen ).

Referencias

Andrii Verbytskyi
fuente
1
Prefiero usar esto sobre otros. Especialmente porque tiene más sentido usar iframes en documentos de origen cruzado (aunque los programadores explotan los iframes la mayoría de las veces) y dado el amplio soporte para esta función en los navegadores.
Fr0zenFyr
1
¡Gracias! Siempre tengo que pasar una hora o más regresando e investigando cómo hacer los mensajes con ejemplos más complicados y detallados. Esto funcionó en 60 segundos. Gracias por un ejemplo sucinto y al grano.
RandallTo
2
Vale la pena plantear eso (de los documentos web de MDN ): siempre proporcione un TargetOrigin específico, no *, si sabe dónde debe ubicarse el documento de la otra ventana. No proporcionar un objetivo específico revela los datos que envía a cualquier sitio malicioso interesado
ZalemCitizen
20

He publicado esto como una respuesta separada, ya que no está relacionado con mi respuesta existente.

Este problema surgió recientemente nuevamente para acceder a un padre desde un iframe que hace referencia a un subdominio y las correcciones existentes no funcionaron.

Esta vez, la respuesta fue modificar el documento dominio de la página principal y el iframe para que sea el mismo. Esto engañará a las mismas verificaciones de la política de origen al pensar que coexisten exactamente en el mismo dominio (los subdominios se consideran un host diferente y fallan la misma verificación de la política de origen).

Inserte lo siguiente en la <head>página en el iframe para que coincida con el dominio principal (ajuste para su doctype).

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

Tenga en cuenta que esto arrojará un error en el desarrollo localhost, por lo tanto, use una verificación como la siguiente para evitar el error:

if (!window.location.href.match(/localhost/gi)) {
    document.domain = "mydomain.com";
} 
Ash Clarke
fuente
¿Y qué hay de probar esto en localhost? alguna solución para eso?
Umesh Awasthi
Consulte: "Tenga en cuenta que esto arrojará un error en el desarrollo localhost, así que use una verificación como la siguiente para evitar el error"
Ash Clarke
2
Vale la pena señalar que (al menos en Google Chrome), ambos, padre e hijo, DEBEN CONFIGURAR document.domain, incluso si uno de ellos ya es "correcto". Ejemplo: Parent is example.comiframe is abc.example.com, then parent and iframe deben llamardocument.domain = "example.com"
KillerX
Sí, eso es correcto, hice un error tipográfico aquí: "la página en el iframe es la misma" debe ser "página y el iframe para ser el mismo". ..... ¡Gracias!
Ash Clarke
para if () ¿por qué no usarías if (document.domain! = "mydomain.com"? Además, estoy confundido, ¿va el <script> en la ventana principal o el iFrame? document.domain en iFrame genera "Error al establecer la propiedad 'dominio' en 'Documento': 'localhost' no es sufijo de 'sc-localhost'.
user2568374
18

Puedes usar

window.top

ver lo siguiente

<head>
    <script>
    function abc() {
        alert("sss");
    }
    </script>
</head>
<body>
    <iframe id="myFrame">
        <a onclick="window.top.abc();" href="#">Click Me</a>
    </iframe>
</body>
Vinothkumar Arputharaj
fuente
Al intentar llamar a parent.custom_function (); desde un iframe no funciona, puede encontrar window.top.custom_function (); trabajará. Funciona para mí por alguna extraña razón. Mis javascripts en la ventana principal están incrustados en el pie de página, leí en alguna parte que incluir archivos javascript en el pie de página causa el problema parent.custom_function () no funciona.
Friso Horstman
@Vinothkumar, una pregunta por favor, ¿cuál es la diferencia entre llamar a "window.top.abc ()" que llamar solo a "abc ()", gracias de antemano =)
Zilev av
@Zilev av El punto completo de este hilo es llamar a una función en un documento primario desde un iframe secundario. Esa es la diferencia. Las llamadas abc()solo funcionarían si function abc()se declararan en el iframe y no en la página principal. window.top.abc()sale del iframe en el documento padre.
Sean Kendle
3

Otra adición para quienes lo necesitan. La solución de Ash Clarke no funciona si están usando protocolos diferentes, así que asegúrese de que si usa SSL, su iframe también usa SSL o se romperá la función. Sin embargo, su solución funcionó para los dominios en sí, así que gracias por eso.

Devon
fuente
2

La solución dada por Ash Clarke para subdominios funciona muy bien, pero tenga en cuenta que debe incluir el documento.domain = "mydomain.com"; tanto en el encabezado de la página de iframe como en el encabezado de la página principal, como se indica en el enlace, las mismas verificaciones de la política de origen

Una extensión importante de la misma política de origen implementada para el acceso DOM de JavaScript (pero no para la mayoría de los otros tipos de comprobaciones del mismo origen) es que dos sitios que comparten un dominio común de nivel superior pueden optar por comunicarse a pesar de fallar el "mismo host" compruebe estableciendo mutuamente su propiedad document.domain DOM correspondiente en el mismo fragmento calificado y a la derecha de su nombre de host actual. Por ejemplo, si http://en.example.com/ y http://fr.example.com/ ambos establecen document.domain en "example.com", serían desde ese punto considerados del mismo origen para el propósito de la manipulación DOM.

Frato
fuente
Sí, eso es correcto, hice un error tipográfico aquí: "la página en el iframe es la misma" debe ser "página y el iframe para ser el mismo". ..... ¡Gracias!
Ash Clarke
¿Qué hay de ejecutar archivos en la computadora local? ¿Cuál es el valor de document.domain?
Raptor
Será localhostla dirección IP de la máquina (normalmente 127.0.0.1), dependiendo de lo que esté en la barra de direcciones URL.
Ash Clarke
2

parent.abc () solo funcionará en el mismo dominio debido a razones de seguridad. Probé esta solución y la mía funcionó perfectamente.

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

Espero que esto ayude. :)

Seph Remotigue
fuente
Esto también es realmente un uso para el documento del iframe, agregando complicaciones masivas si necesita consultar los controles en el formulario principal.
Paul
1

Con Firefox y Chrome puedes usar:

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

Si myfunction está presente tanto en el iframe como en el padre, se llamará al padre.

copo de nieve
fuente
No funciona. Aquí está mi demo: dotku.github.io/tech/html/iframe/iframe_function_container.html
Weijing Jay Lin
Como lo indicó Ash Clarke, el javascript que desea llamar desde el iframe secundario debe estar en la cabeza del padre.
copo de nieve
La respuesta aceptada no necesita que el guión esté en la cabeza. No probé si esta solución ya no necesita que el script esté en la cabeza o no.
Guy Schalnat
0

Si bien algunas de estas soluciones pueden funcionar, ninguna de ellas sigue las mejores prácticas. Muchos asignan variables globales y puede encontrarse haciendo llamadas a múltiples variables o funciones principales, lo que lleva a un espacio de nombres desordenado y vulnerable.

Para evitar esto, use un patrón de módulo. En la ventana principal:

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

var newThing = Object.create(myThing);

Luego, en el iframe:

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

Esto es similar a los patrones descritos en el capítulo de Herencia del texto seminal de Crockford, "Javascript: The Good Parts". También puede obtener más información en la página de w3 sobre las mejores prácticas de Javascript. https://www.w3.org/wiki/JavaScript_best_practices#Avoid_globals

William J. Littlefield
fuente