window.postMessage 实现跨窗口进行通信

59 min read

window.postMessage 是一种 JavaScript API,它允许跨窗口进行通信。它可用于在两个不同页面之间(或两个不同域名的页面)进行通信。具体来说,它允许父窗口和子窗口之间进行通信,也可用于在多个标签页之间进行通信。

这个方法接受两个参数,第一个参数是要发送的信息,第二个参数是信息要发送到的窗口的目标网址。

Example:

// 需要其他窗口的 window 对象来调用 postMessage ,这才监听 message 事件才会被触发
var child = window.open("https://example.com/child.html", "Child Window");

 // type 是为了区别和别的应用发送的消息,最后一个参数如果是 '/' 表示只在当前域下有效
child.postMessage("Hello from the parent!", "https://example.com");

//in the child window
window.addEventListener("message", receiveMessage, false);

function receiveMessage(event) {
  console.log("Received message: " + event.data);
}

这样,在父窗口中调用 postMessage 方法后,将在子窗口中调用 receiveMessage 函数并打印出 "Received message: Hello from the parent!"。

image-20230111140339817

otherWindow.postMessage(message, targetOrigin, [transfer]);
参数 说明
otherWindow 其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行 window.open 返回的窗口对象、或者是命名过或数值索引的 window.frames。
message 将要发送到其他 window的数据。
targetOrigin 指定哪些窗口能接收到消息事件,其值可以是 *****(表示无限制)或者一个 URI。
transfer 可选,是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

示范

<h1>这是 T1</h1>
<button id="btn1">打开t2</button>
<button id="btn2">发送消息到t2</button>
<pre id="text"></pre>

<script>
  var t2
  var btn1 = document.getElementById('btn1')
  var btn2 = document.getElementById('btn2')
  var text = document.getElementById('text')

  btn1.addEventListener('click', function() {
    t2 = window.open('/t2.html')
    // 若t2页面没有重写 onload 方法,则在t1页面这么写是ok的,但若t2页面已重写 onload 方法,则以下方法不生效。
    t2.onload = () => {
      btn2.click()
    }
    // 可以改写为以下写法
    t2.window.addEventListener('load', function() {
        btn2.click()
    })
  })

  btn2.addEventListener('click', function() {
    console.log('btn2 点击');
    t2.postMessage({type: 'popring', message: 't1 发送出去的消息'}, '/')
  })

  window.addEventListener('message', function(event) {
    // 过滤非当前域下的消息
    if(event.origin !== 'http://127.0.0.1:5500' || !event.data) {
      return
    }
    // 过滤其他非本应用传递过来的消息,例如 chrome 的插件就可能也会发送消息(表示 wappalyzer 就会)
    if(event.data?.type !== 'popring') {
      return
    }
    text.innerText += (JSON.stringify(event.data)+'\n')
  })
</script>
<h1>这是 T2</h1>
<button id="btn">发送消息到 t1</button>
<pre id="text"></pre>

<script>
  var btn = document.querySelector('#btn')
  var text = document.getElementById('text')
  var t1
  
  // t2 定义的 onload 事件
  window.onload = function() {
    console.log('t2 onload');
  }
  
  
  btn.addEventListener('click', function() {
    t1.postMessage({type: 'popring', message: 't2 发送出去的消息'}, '/')
  })

  window.addEventListener('message', function(event) {
    if(event.origin !== 'http://127.0.0.1:5500' || !event.data) {
      return
    }
    if(event.data?.type !== 'popring') {
      return
    }
    t1 = event.source
    text.innerText += (JSON.stringify(event.data)+'\n')
  })
</script>