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 mediantemyIFRAME.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 utilizandomyIFRAME.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 siemprefalse
y las propiedades de acceso deevent.source
llevan a errores deAccess 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);