postMessage源IFrame

ski*_*rk1 21 javascript iframe html5 postmessage cross-domain

我正在开发一个网站,其中包含使用postMessage调整到正确高度的跨域iframe.我唯一的问题是确定哪个iframe具有哪个高度.我目前设置的方式是,当一个iframe将其高度发送给父级时,所有iframe的高度都会更改.

家长:

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);
Run Code Online (Sandbox Code Playgroud)

IFRAME:

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

有没有办法确定哪个iframe发送了这个message事件?

Jac*_*ack 19

我从这里找到了解决方案:如何在JavaScript中共享窗口和框架之间的数据

家长:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @RandyHall:是的,此外,为了管理跨域问题.我将评论提升为一个更好理解的答案,请参阅http://stackoverflow.com/a/20404180/698168 (2认同)

Jul*_*egg 19

是的,你可以识别出做过的IFRAME postMessage.有不同的情况:

  • 源IFRAME具有与http://example.com/接收消息的窗口相同的URL(例如):使用标识IFRAME

    myIFRAME.contentWindow == event.source

  • 源IFRAME具有与/myApp/myPage.html父HTML页面相同的源但相对URL(例如):使用标识IFRAME

    myIFRAME.contentWindow == event.source.parent

  • 源IFRAME有一个跨源URL(例如http://example.com/)接收消息的页面不同(例如http://example.org/):上述方法不起作用(比较总是false并且访问event.source导致Access Denied错误的属性)并且必须基于IFRAME识别在其起源域;

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

为了管理这三种不同的情况,我使用以下内容:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对于跨域URL,请注意,如果event.origin是多个IFRAME共有的域,则无法区分真正的源.

有些人使用===而不是==在这种情况下我没有发现任何差异,所以我使用最短的比较器.

此实现已经过测试,可在以下位置工作:

  • MSIE 9
  • Firefox 17

作为替代方案(由Griffin建议),您可以使用具有唯一标识符(例如时间戳)的IFRAME src,并且IFRAME的Web应用程序将在发布的消息中发回该唯一标识符.虽然IFRAME标识会更简单,但这种方法需要修改IFRAME的Web应用程序(这并不总是可行).这也可能导致安全问题(例如,IFRAME的Web应用程序试图猜测其他IFRAME应用程序的唯一标识符).

  • 你可能最好只使用时间戳查询字符串确保每个iframe都有一个唯一的href,然后在跨文档消息中包含源href. (2认同)

deC*_*ene -2

该事件还应该有一个属性“source”,可以与 iframe 的“contentWindow”属性进行比较。