【问题标题】:How to communicate between iframe and the parent site?iframe 和父站点之间如何通信?
【发布时间】:2012-02-27 12:49:37
【问题描述】:

iframe 中的网站不在同一个域中,但两者都是我的,我想在iframe 和父网站之间进行通信。有可能吗?

【问题讨论】:

    标签: javascript html ajax iframe


    【解决方案1】:

    使用不同的域,无法直接调用方法或访问 iframe 的内容文档。

    你必须使用cross-document messaging

    父-> iframe

    例如在顶部窗口中:

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

    在 iframe 中:

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

    iframe -> 父级

    例如在顶部窗口中:

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

    在 iframe 中:

    window.top.postMessage('hello', '*')
    

    【讨论】:

    • 谢谢,但不幸的是它在旧浏览器中不起作用。
    • 在父级中:window.onmesage = function()...。在 iframe 中:window.top.postMessage('hello', '*')
    • 这不是错误。文件 url 可能非常不安全,浏览器越来越小心地对待它们。回到过去,您可以在网页上放置指向file://C:/Windows/system32/whatever 的链接,并将其指向用户的系统文件夹。如今,浏览器大多会忽略对此类链接的点击。运行一个网络服务器并通过它访问你的代码,你会看到错误消失了。
    • 作为一个好习惯,永远不要使用'*'作为你的目标。事实上,MDN 说 - “如果您知道其他窗口的文档应该位于何处,请始终提供特定的 targetOrigin,而不是 *。未能提供特定的目标会泄露您发送到任何感兴趣的恶意站点的数据。”
    • 我们甚至可以使用window.frames[index]来获取子框架(<iframe>, <object>, <frame>),相当于getElementsByTagName("iframe")[index].contentWindow。要从 IFrame 中获取父窗口对象,最好使用window.parent,因为window.top 代表最顶层的父窗口
    【解决方案2】:

    在 2018 年和现代浏览器中,您可以将自定义事件从 iframe 发送到父窗口。

    iframe:

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

    父母:

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

    PS:当然,你可以用同样的方式向相反的方向发送事件。

    document.querySelector('#iframe_id').contentDocument.dispatchEvent(event)
    

    【讨论】:

    • 你好,我必须在同一个域上吗?
    • 需要注意的是,所有主流浏览器都支持dispatchEvent。 IE9 是它的第一个版本,所以现在大多数操作系统都可以使用它。 caniuse.com/#search=dispatchEvent
    • 我无法使用此方法从父级与 iframe 进行通信。
    • Avan 和@radtek 有一个简单的解决方案。您所要做的就是首先从 iframe 向父级发送一个事件,通知父级 iframe 已加载(本质上是“就绪消息”)。父级将监听消息,如果它接收到“就绪消息”事件,它可以使用您要发送的任何消息回复 iframe。这样,它仅在 iframe 加载后才将消息发送到 iframe。当然,iframe 页面只有在加载后才会将消息发送给父级。
    【解决方案3】:

    使用event.source.window.postMessage 发回给发件人。

    来自 iframe

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

    然后父母说回来。

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

    【讨论】:

    【解决方案4】:

    你也可以使用

    postMessage(message, '*');

    【讨论】:

    【解决方案5】:

    window.top 属性应该能够满足您的需求。

    例如

    alert(top.location.href)
    

    http://cross-browser.com/talk/inter-frame_comm.html

    【讨论】:

    • 由于 iframe 不在同一个域中,他无法访问其父级。
    【解决方案6】:

    这个库支持 HTML5 postMessage 和带有 resize+hash https://github.com/ternarylabs/porthole的旧版浏览器

    编辑:现在在 2014 年,IE6/7 的使用率很低,IE8 及以上都支持postMessage,所以我现在建议只使用它。

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

    【讨论】:

    • 需要注意的是 IE8/9 仅支持字符串 caniuse.com/#search=postmessage(参见已知问题)
    • 这可以通过将事件对象编码为 json 并在另一端解码来解决。
    猜你喜欢
    • 2011-03-12
    • 2011-12-10
    • 2019-09-29
    • 2011-03-14
    • 2011-03-03
    • 2013-05-15
    • 1970-01-01
    • 2019-10-31
    相关资源
    最近更新 更多