¿Cómo comunicarse entre iframe y el sitio principal?

193

El sitio web en el iframe no está ubicado en el mismo dominio , pero ambos son míos, y me gustaría comunicarme entre el iframey el sitio principal. ¿Es posible?

Danny Fox
fuente

Respuestas:

322

Con diferentes dominios, no es posible llamar a métodos o acceder directamente al documento de contenido del iframe.

Tienes que utilizar la mensajería entre documentos .

Por ejemplo en la ventana superior:

 myIframe.contentWindow.postMessage('hello', '*');

y en el iframe:

window.onmessage = function(e){
    if (e.data == 'hello') {
        alert('It works!');
    }
};

Si está publicando un mensaje desde iframe a la ventana principal

window.top.postMessage('hello', '*')
usuario123444555621
fuente
2
gracias, pero lamentablemente no funciona en navegadores antiguos.
Danny Fox
106
En los padres: window.onmesage = function().... En el iframe:window.top.postMessage('hello', '*')
user123444555621
4
No es un error. Las URL de archivos pueden ser muy inseguras y los navegadores las tratan con cada vez más cuidado. En los viejos tiempos, podía poner un enlace a file://C:/Windows/system32/whateveruna página web y hacer que apuntara directamente a la carpeta del sistema del usuario. En la actualidad, los navegadores ignoran en su mayoría los clics en enlaces como ese. Ejecute un servidor web y acceda a su código a través de él y verá que los errores desaparecen.
Stijn de Witt
4
Como buena práctica, nunca use el '*' para su objetivo. De hecho, MDN dice: "Proporcione siempre un origen de destino específico, no *, si sabe dónde debe ubicarse el documento de la otra ventana. No proporcionar un destino específico revela los datos que envía a cualquier sitio malicioso interesado".
rodiwa
2
Incluso podemos usar window.frames[index]para obtener child frame ( <iframe>, <object>, <frame>), equivalente a getElementsByTagName("iframe")[index].contentWindow. Para obtener el objeto de la ventana principal de IFrames, es mejor usarlo window.parent, ya que window.toprepresenta la ventana principal más importante
phoenisx
49

Debe estar aquí, porque respuesta aceptada de 2012

En 2018 y en los navegadores modernos, puede enviar un evento personalizado desde iframe a la ventana principal.

iframe:

var data = { foo: 'bar' }
var event = new CustomEvent('myCustomEvent', { detail: data })
window.parent.document.dispatchEvent(event)

padre:

window.document.addEventListener('myCustomEvent', handleEvent, false)
function handleEvent(e) {
  console.log(e.detail) // outputs: {foo: 'bar'}
}

PD: Por supuesto, puede enviar eventos en la misma dirección opuesta.

document.querySelector('#iframe_id').contentDocument.dispatchEvent(event)
Extraño en la Q
fuente
2
Hola, ¿tengo que estar en el mismo dominio para hacerlo?
Guillaume Harari
1
Cabe señalar que dispatchEventes compatible con todos los principales navegadores. IE9 fue la primera versión en la que vino, por lo que la mayoría de los sistemas operativos ahora funcionan con él. caniuse.com/#search=dispatchEvent
Dan Atkinson
1
No puedo comunicarme de padre a iframe con este método.
Avan
Sí, tampoco puedo hacer que funcione, el iframe js se está cargando después de la ventana principal, por lo que no está allí para recibir el mensaje cuando se envía. solo funciona de iframe a padre para mí.
radtek
14

Esta biblioteca es compatible con HTML5 postMessage y navegadores heredados con cambio de tamaño + hash https://github.com/ternarylabs/porthole

Editar: Ahora, en 2014, el uso de IE6 / 7 es bastante bajo, IE8 y, sobre todo, el soporte, postMessagepor lo que ahora sugiero usarlo.

https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage

jpillora
fuente
Con la advertencia de que IE8 / 9 solo admite cadenas caniuse.com/#search=postmessage (Ver problemas conocidos)
Harry
esto se puede solucionar codificando sus objetos de evento en json y decodificándolos en el otro lado.
codewandler
3

Úselo event.source.window.postMessagepara enviar de vuelta al remitente.

Desde Iframe

window.top.postMessage('I am Iframe', '*')
window.onmessage = (event) => {
    if (event.data === 'GOT_YOU_IFRAME') {
        console.log('Parent received successfully.')
    }
}

Luego, de los padres, responda.

window.onmessage = (event) => {
    event.source.window.postMessage('GOT_YOU_IFRAME', '*')
}
Binh Ho
fuente
1

También puedes usar

postMessage(message, '*');

gonzarodriguezt
fuente
no es demasiado informativo, he intentado describir el proceso en mi publicación de blog alfilatov.com/posts/…
Alex Filatov