pass open from event ejemplo data javascript html5 iframe cross-domain postmessage

javascript - open - window addeventlistener iframe



postMessage Source IFrame (6)

El evento también debe tener una propiedad "fuente" que pueda compararse con la propiedad iframes "contentWindow".

Estoy trabajando en un sitio web con iframes de dominios cruzados que se redimensionan a la altura correcta usando postMessage. El único problema que tengo es identificar qué iframe tiene qué altura. La forma en que lo tengo configurado es que cuando un iframe envía su altura al padre, se cambian las alturas de todos los iframes.

Padre:

var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; var eventer = window[eventMethod]; var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message"; eventer(messageEvent, function(e) { $(''iframe'').height(e.data); }, false);

Iframe:

var updateHeight = function() { if(window.parent) { window.parent.postMessage($(''.widget'').outerHeight(), ''*''); } };

¿Hay alguna manera de identificar qué iframe envió el evento de message ?


He encontrado la solución desde aquí: Cómo compartir datos entre una ventana y un marco en JavaScript

Padre:

var frames = document.getElementsByTagName(''iframe''); for (var i = 0; i < frames.length; i++) { if (frames[i].contentWindow === event.source) { $(frames[i]).height(event.data); //the height sent from iframe break; } }


Los siguientes trabajos para mí son de origen cruzado:

window.addEventListener(''message'', function (event) { if (event.data.size) { Array.prototype.forEach.call(document.getElementsByTagName(''iframe''), function (element) { if (element.contentWindow === event.source) { element.style.height = `${event.data.size.height}px`; } }); } }, false);

Probado en Chromium 64 y Firefox 59.


Sí, puede identificar el IFRAME que realizó el postMessage . Hay diferentes situaciones:

  • El IFRAME de origen tiene la misma URL de origen (por ejemplo, http://example.com/ ) que la ventana que recibe el mensaje: el IFRAME se identifica mediante

    myIFRAME.contentWindow == event.source

  • El IFRAME de origen tiene una URL del mismo origen pero relativa (por ejemplo, /myApp/myPage.html ) a la página HTML principal: el IFRAME se identifica utilizando

    myIFRAME.contentWindow == event.source.parent

  • El IFRAME de origen tiene una URL de origen cruzado (por ejemplo, http://example.com/ ) diferente de la página que recibe el mensaje (por ejemplo, http://example.org/ ): los métodos anteriores no funcionan (la comparación es siempre false y las propiedades de acceso de event.source llevan a errores de Access Denied ) y el IFRAME debe identificarse en función de su dominio de origen;

    myIFRAME.src.indexOf(event.origin)==0

Para manejar estas tres situaciones diferentes, estoy usando lo siguiente:

var sourceFrame = null; // this is the IFRAME which send the postMessage var myFrames = document.getElementsByTagName("IFRAME"); var eventSource = event.source; // event is the event raised by the postMessage var eventOrigin = event.origin; // origin domain, e.g. http://example.com // detect the source for IFRAMEs with same-origin URL for (var i=0; i<myFrames.length; i++) { var f = myFrames[i]; if (f.contentWindow==eventSource || // for absolute URLs f.contentWindow==eventSource.parent) { // for relative URLs sourceFrame = f; break; } } // detect the source for IFRAMEs with cross-origin URL (because accessing/comparing event.source properties is not allowed for cross-origin URL) if (sourceFrame==null) { for (var i=0; i<myFrames.length; i++) { if (myFrames[i].src.indexOf(eventOrigin)==0) { sourceFrame = myFrames[i]; break; } } }

Para las URL de varios dominios, tenga en cuenta que no podemos diferenciar la fuente verdadera si event.origin es un dominio común a más de un IFRAME.

Algunas personas usan === lugar de == pero no encontré ninguna diferencia en este contexto, así que estoy usando el comparador más corto.

Esta implementación ha sido probada y funciona bajo:

  • MSIE 9
  • Firefox 17

Como alternativa (sugerida por Griffin), puede usar un src de IFRAME con un idenfitier único (por ejemplo, marca de tiempo), y la aplicación web de IFRAME devolverá este identificador único en los mensajes publicados. Si bien la identificación de IFRAME sería más simple, este enfoque requiere modificar la aplicación web de IFRAME (lo que no siempre es posible). Esto también puede llevar a problemas de seguridad (por ejemplo, la aplicación web de IFRAME) intenta adivinar el identificador único de otras aplicaciones de IFRAME.


Si el iframe de origen está anidado en más de un iframe principal, entonces deberá recurrir sobre la propiedad window.frames de cada iframe y compararlo con la propiedad de origen messageEvent #.

Por ejemplo, si el mensaje es generado por iframe # level3 de este Dom.

<iframe Id=level1> <iframe Id=level2> <iframe Id=level3 /> </iframe> </iframe>

Debería poder encontrar el índice del iframe del antepasado en la ventana actual usando.

FindMe = event.source FrameIndex = find(window) frames[FrameIndex].frameElement == getElByTagName(iframe)[FrameIndex] function find(target){ for (i=0; I< target.frames.length; i ++) if(target.frames[i] == FindMe || find(target.frames[i])) return i return false }

Es importante tener en cuenta que

La propiedad Window.frames no está restringida por la política de dominio cruzado

Esta técnica funcionará independientemente de cuán profundamente anidado esté el iframe de origen.

window.frames es una colección de objetos de ventana, no elementos iframe.

el acceso a las propiedades de los miembros de la colección window.frames está restringido por Same Origin (es decir, es posible que no pueda acceder a las propiedades frameElement o location de window.frames [i]


Tengo una idea para resolver este problema. cuando cree el iframe, asigne un nombre / id al iframe. .

y, en el script dentro de iframe, envíe el mensaje como un objeto que se verá como

window.parent.postMessage({"height" : $(''.widget'').outerHeight(), "frmname" : window.name}, ''*'');

en el oyente padre,

eventer(messageEvent, function(e) {`enter code here` $(e.data.frmname).height(e.data.height); }, false);