postMessage的来源的IFrame(postMessage Source IFrame)

2019-07-21 07:33发布

我的工作与被调整到使用的postMessage正确的高度跨域iFrame的网站上。 我遇到的唯一问题是确定哪个iframe具有高度。 我目前得到它成立的方式是,当一个IFRAME将其高度与父,所有的I帧的身高被改变。

家长:

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(), '*');
    }
};

有没有一些方法来确定哪些iframe中发送的message的事件吗?

Answer 1:

我发现从这里的解决方案: 如何将一个窗口和一个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;
    }
}


Answer 2:

是的,你可以找出哪些做了该IFRAME postMessage 。 有不同的情况:

  • 源IFRAME具有相同的来源的URL(例如http://example.com/ ),其接收消息的窗口:所述IFRAME使用识别

    myIFRAME.contentWindow == event.source

  • 源IFRAME具有相同来源,但相对URL(/myApp/myPage.html )父HTML页面:在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;
        }
    }
}

对于跨网域网址,请注意,如果我们不能区分真实来源event.origin是不止一个IFRAME中常见的域。

有些人用===代替==但我没有发现在这方面有什么区别,所以我用最短的比较。

这种实现已通过测试并下工作:

  • MSIE 9
  • 火狐17

作为替代方案(由格里芬的建议),你可以使用一个IFRAME SRC具有独特idenfitier(如时间戳),以及IFRAME'd Web应用程序将在发布的消息发回的这个唯一的标识符。 虽然IFRAME识别会更简单,这种方法需要修改IFRAME'd Web应用程序(这并不总是可能的)。 这也可能会导致安全问题(如IFRAME'd Web应用程序试图猜测其他的IFRAME应用程序的唯一标识符)。



Answer 3:

我有一个想法来解决这个问题。 当您创建的iframe赋予一个名字/ id来的iframe。 。

并且,在内部的iframe的脚本发送消息的对象,看起来像

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

在父母的倾听者,

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


Answer 4:

如果源的iframe嵌套在多个父iframe中,那么你就需要递归在每个iframe的window.frames财产和比较反对的MessageEvent#源属性。

例如,如果通过该Dom。的#IFRAME Level3的生成的消息。

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

您应该能够找到祖先iframe的指数使用当前窗口。

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 
}

它需要注意的是

该Window.frames财产不受跨域策略限制

不管这种技术将工作源iframe的情况如何深度嵌套是

window.frames是窗口对象不是IFRAME元素的集合。

访问window.frames收集的承包商,客人的propetties s被同源resttictred(即你可能无法访问window.frames的frameElement或位置属性[I]



Answer 5:

我跨域了以下工作:

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

经测试,在铬64和Firefox 59。



Answer 6:

本次活动还应该有一个属性的“源”,它可以比I帧“contentWindow”属性。



文章来源: postMessage Source IFrame