使用window对象传递消息

window对象传递消息

随着前端业务逻辑的愈发复杂化,常需要在不同窗口之间进行数据通信,本文介绍了如何使用message事件进行数据通信的行为。

1. window.top对象

window.top是在Web浏览器环境中使用的JavaScript全局对象,它提供了对顶级窗口的引用。顶级窗口是当前浏览器标签页或窗口层次结构中的最高级别窗口。

以下是一些关于 window.top 的重要信息:

  • window.top 提供了对顶级窗口的引用,通常是指当前浏览器标签页的最顶层窗口对象。这个顶级窗口对象可以访问和操作整个窗口层次结构,包括其他嵌套框架或窗口。
  • 通过 window.top,你可以访问顶级窗口的属性和方法,例如 window.top.document 表示顶级窗口的文档对象,window.top.location 表示顶级窗口的URL地址等。
  • 使用 window.top 可以方便地在嵌套的框架或窗口之间进行通信和操作 。通过 window.top 对象,可以向上遍历窗口层次结构,与其他同级或父级窗口进行交互。
  • 需要注意的是,由于安全性限制,跨域的窗口访问可能会受到限制。如果脚本位于不同的域名或协议下,访问 window.top 的属性和方法可能会受到同源策略的限制

总之,window.top 是一个指向顶级窗口对象的引用,它提供了在Web浏览器环境中访问和操作顶级窗口的功能,用于处理窗口间的通信和操作

2. window对象和消息机制

  • iframe标签对象上有一个名为contentWindow的对象,这个对象存在的价值为:当A.html中使用ifame引用b.html的时候,b文档对应的contentWindow对象实际上提供了a和b进行通信的接口;
  • contentWindow对象是b文档在a文档中被引用的时候的接口对象,记为contentWindow::BinA ,对应的是b文档本身的window对象,记为window::BinB ,数据流从a到b的过程,实际上是从contentWindow::BinAwindow::BinB的过程;
  • 也就是contentWindow::BinA发消息,而window::BinB接受消息:
js 复制代码
// a.html
contentWindow.postMessage('msg from a', '*')
js 复制代码
// b.html
window.addEventListener('message', function(e){
    console.log(e.data);
})

3. contentWindow对象的获取

强调一下:contentWindow对象是iframe标签对象的一个属性:

js 复制代码
const contentWindow = document.getElementById("bFrame").contentWindow;

4. iframe的name属性

在iframe标签上设置name属性,可以方便在通信过程中识别数据源,如下:

html 复制代码
<iframe src="b.html" id="bFrame" name="bFrame" style="width:100%;height:600px;"></iframe>

5. message事件的事件对象

window使用addEventListener监听message事件,对应的事件对象e中有两个常用的属性:

  • data: 其值为传递的数据
  • source: 表示数据源,数据源的类型是Window

6. 实例

6.1 项目结构

bash 复制代码
mkdir test-window && cd test-window
touch index.html parent.html child.html

6.2 index.html中的内容

html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <title>Communication Example</title>
    <script>
      function sendMessageToParent() {
        // 1. 找到文档对应的接口对象contentWindow
        var parentFrame = document.getElementById("parentFrame").contentWindow;
        // 2. 使用contentWindow上的postMessage方法传递信息
        parentFrame.postMessage("Hello from top Window!", "*");
      }
    </script>
  </head>
  <body>
    <h1>Communication Example</h1>
    <!-- 点击按钮之后获取parent.html对应的window对象,使用这个对象上的postMessage向parent.html传递消息
    也就是说,contentWindow是内嵌html提供的通信接口 -->
    <button onclick="sendMessageToParent()">Send Message to Parent</button>

    <iframe src="parent.html" id="parentFrame" name="parentFrame" style="width:100%;height:600px;"></iframe>
  </body>
</html>

6.3 parent.html中的内容

html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <title>Parent Window</title>
  </head>
  <body>
    <h1>Parent Window</h1>

    <iframe src="child.html" id="childFrame" name="childFrame" style="width:100%;height:400px;"></iframe>

    <script>
      // 1. 本文档的window对应的就是在其它文档中标签对象上的contentWindow属性
      // 2. 使用window监听message事件,即可订阅从其他文档中通过postMessage方法传递过来的信息
      window.addEventListener("message", function(event) {
        if (event.source === window.top) {
          console.log("Message received from Top Window:", event.data);
          // 3. 将收到的消息传递给下一层文档
          transformMessageToChild(event.data);
        }
      });
      
      // 4. 同样是先获取contentWindow,然后使用其传递消息
      function transformMessageToChild(data) {
        var childFrame = document.getElementById("childFrame").contentWindow;
        childFrame.postMessage(`(msg from top, delivered by parent) ${data}`, "*");
      }
    </script>
  </body>
</html>

6.4 child.html

html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <title>Child Frame</title>
  </head>
  <body>
    <h1>Child Frame</h1>

    <script>
      window.addEventListener("message", function(event) {
        if (event.source.name === "parentFrame") {
          console.log("Message received from Parent Window:", event.data);
        }
      });
    </script>
  </body>
</html>

效果

点击按钮之后,控制台打印的内容:

plaintext 复制代码
Message received from Top Window: Hello from top Window!                                            parent.html:26 
Message received from Parent Window: (msg from top, delivered by parent) Hello from top Window!     child.html:12

7. 补充:postMessage的第二个参数

  • postMessage() 方法中,第二个参数(targetOrigin)指定了目标窗口的来源。

  • '*' 作为 targetOrigin 参数传递给 postMessage() 方法时,它表示可以接受来自任何源(包括不同的域、协议和端口)发送的消息。具体来说,'*' 是一个通配符,用于指示无论来源是什么,都可以接收消息。这意味着消息会被发送到目标窗口的所有窗口对象(即 window 对象)。

  • 在真实的生产环境中,使用 '*' 应谨慎。因为它允许接受来自任何来源的消息,可能存在安全风险。为了确保安全性,最好将 targetOrigin 参数设置为确切的值,以限制只接受来自特定源的消息。

  • 例如,如果你的目标窗口是位于 https://example.com 域名下的页面,你可以将 targetOrigin 设置为该域名:

javascript 复制代码
childFrame.postMessage("Hello from Parent Window!", "https://example.com");

这样,只有来自 https://example.com 域名的窗口发送的消息才会被接受。其他来源的消息将被忽略,从而提供了更严格的安全性。

相关推荐
我命由我1234519 分钟前
Vue 开发问题:Missing required prop: “value“
开发语言·前端·javascript·vue.js·前端框架·ecmascript·js
16年上任的CTO19 分钟前
一文讲清楚React中的key值作用与原理
前端·javascript·react.js·react key
阳火锅27 分钟前
在生产环境下,你真的有考虑到使用数组方法的健壮性吗?
前端·javascript·面试
孤月葬花魂38 分钟前
JavaScript 中的 Promise API 全面解析
前端·javascript
几道之旅39 分钟前
Electron 应用打包全指南
前端·javascript·electron
shushushu44 分钟前
Web如何自动播放音视频
前端·javascript
前端进阶者1 小时前
天地图InfoWindow插入React自定义组件
前端·javascript
扶我起来还能学_1 小时前
uniapp Android&iOS 定位权限检查
android·javascript·ios·前端框架·uni-app
爱学习的茄子1 小时前
JavaScript闭包实战:防抖的优雅实现
前端·javascript·面试
前端付豪1 小时前
9、前端日志埋点系统的架构设计
前端·javascript·架构