【问题标题】:Can not access iframe elements of cross domain using postmessage无法使用 postmessage 访问跨域的 iframe 元素
【发布时间】:2020-05-04 16:26:25
【问题描述】:

我正在使用两个网站。我在一个网站项目中有一个带有母版页的 aspx 页面。我想在另一个也有母版页的页面中将此页面用作我的第二个网站中的 iframe。当我这样做时,我得到了两个母版页,而我想从我的 iframe 中删除母版页。

简单来说,如何从不同域的顶部窗口访问子窗口的元素?

首先,我尝试从页面 preInit 事件中的代码替换母版页,但我无法获取子页的母版页。所以这对我不起作用。

第二个解决方案我试图从 jquery 中删除它。在这里,我无法访问 iframe 的内容,因为它来自不同的域。所以,我使用了 Post-message 但仍然出现同样的问题。这是我的代码,我试过了。

在父页面中:

window.addEventListener("message", function (e) {
        alert(e.origin);
        if (e.origin !== 'http://localhost:xxxxx') {
            return;
        }
        alert(e.data);

    }, false);

在 iframe 页面中:

$(document).ready(function () {
       window.parent.postMessage("I am loaded", "*");
    });

我在我的 postmessage 中收到消息,但仍然无法访问 iframe 中的元素(在我的情况下为 e.source)。

请帮忙!

【问题讨论】:

    标签: javascript html iframe postmessage


    【解决方案1】:

    简单地说,如何从不同域的顶部窗口访问子窗口的元素?

    你不能。您只能在文档之间发布消息

    因此,如果您想对另一个页面上的元素做某事,那么您需要:

    • 发送一条消息,要求对该元素执行该操作
    • 编写代码来监听该消息并执行该操作

    例如

    父页面

    <!DOCTYPE html>
    <meta charset="utf=8">
    <title>Parent</title>
    <script>
        addEventListener(
          "message",
          function(e) {
            if (e.origin !== "http://localhost:8080") {
              return;
            }
            if (e.data.message === "Ready and waiting") {
                console.log("Message recieved from child iframe");
                // Now we know the document has loaded into the frame and is ready to recieve messages. 
                document.querySelector("iframe").contentWindow.postMessage({
                    message: "Remove",
                    selector: "#b"
                },
                "http://localhost:8080")
            }
          }
        );
    </script>
    <iframe src="http://localhost:8080/frame.html"></iframe>
    

    框架页面

    <!DOCTYPE html>
    <meta charset="utf=8">
    <title>Child</title>
    <div id="a">A</div>
    <div id="b">B</div>
    <div id="c">C</div>
    <script>
        window.parent.postMessage({ message: "Ready and waiting" }, "http://localhost:8081");
    
        addEventListener(
            "message",
            function(e) {
                if (e.origin !== "http://localhost:8081") {
                    return;
                }
                console.log("Message recieved from child iframe", e.data);
                if (e.data.message === "Remove") {
                    document.querySelector(e.data.selector).remove();
                }
            }
        );
    </script>
    

    【讨论】:

    • 我可以在 iframe 加载之前从我的父页面向 iframe 发送消息吗?实际上,Iframe 需要一个 id 来加载,我想从我的父页面中提供它。 @昆汀
    【解决方案2】:

    首先:永远不要使用alert

    改为使用console.log,它自 2010 年以来一直是首选,之所以引入它是因为除了无法记录字符串以外的任何内容(因此将数据强制转换为字符串,从而导致诸如 [Object: object] 之类的废话), alert 函数阻塞了整个 JS 线程。这是过去时代遗留下来的 JS。它在 2010 年以来编写的任何代码中都没有位置,更不用说您今天编写的任何代码了。

    至于您的问题,您不想将消息发布到 window.parent,您需要进行一些功能检测以发现您的发布目标应该在您的 iframe 脚本中:

    const target = parent.postMessage ? parent : (parent.document.postMessage ? parent.document : undefined);
    if (target) {
      target.postMessage({ ... }, "*");
    } else {
      console.error("no valid postMessage target... what browser is this?");
    }
    

    另外,这里 jQuery 用处不大,只需使用 defer 加载脚本并编写不带任何 window.addEventlistener('loaded'....$.ready(....) 的代码,因为 defer 关键字将 take care of that for you(如果您不熟悉defer,自 2012 年以来所有主流浏览器都支持它,所以不用担心 IE 不支持它,例如)。

    【讨论】:

      猜你喜欢
      • 2016-03-02
      • 2011-12-09
      • 2010-11-21
      • 1970-01-01
      • 2014-07-01
      • 2011-08-29
      • 2011-11-23
      • 2013-08-03
      • 1970-01-01
      相关资源
      最近更新 更多