postMessage --iframe父子窗口之间的数据通信

如果你有使用iframe,那么肯定使用过或听过postMessage。这个API并没什么难度可言,就是一般很少使用,等到需要用时又容易忘记怎么使用,在此做个备忘吧。

语法

otherWindow.postWindow(message, targetOrigin, [transfer])
  • otherWindow: 其他窗口的引用
  • message:发送的数据
  • targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串" * "(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。

以下为代码示例

父窗口文件:iframe_parent.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
  </style>
</head>
<body>
  <h6>父窗口</h6>
  <div>
    <input id="input" type="text">
    <button id="send">发消息给子窗口</button>
  </div>
  <p>子窗口的消息:<span id="message"></span></p>
  <br>
  <iframe id="iframe" src="iframe_child.html" frameborder="1"></iframe>

  <script>
    const $ = (s) => {return document.querySelector(s)}
    const btn = $('#send')
    const input = $('#input')
    const message = $('#message')
    const iframe = $('#iframe')

    btn.onclick = () => {
      const data = input.value
      data && sendMessage(data)
    }

    function sendMessage(data) {
      iframe && iframe.contentWindow.postMessage(data)
    }

    window.addEventListener('message', (event) => {
      message.innerHTML = event.data
      // 此处不能再给子窗口发消息,不然会死循环
      // event.source.postMessage(`收到${event.data}了`)
    })
  </script>
</body>
</html>

子窗口文件 iframe_child.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    body{
      background: #eee;
    }
  </style>
</head>
<body>
  <h6>子窗口</h6>
  <div>
    <input id="input" type="text">
    <button id="send">发消息给父窗口</button>
  </div>
  <p>
    父窗口的消息: <span id="message"></span>
  </p>

  <script>
    const $ = (s) => {return document.querySelector(s)}
    const btn = $('#send')
    const input = $('#input')
    const message = $('#message')
    const parent = window.parent

    btn.onclick = () => {
      const data = input.value
      data && sendMessageToParent(data)
    }

    window.addEventListener('message', (event) => {
      console.log('父窗口===', event.source)
      console.log('来自父窗口的消息===', event.data)
      message.innerHTML = event.data
      event.source.postMessage(`收到(${event.data})了`)
    })

    function sendMessageToParent (data) {
      parent && parent.postMessage(data)
    }

  </script>
</body>
</html>

遇到报错:Failed to execute ‘postMessage’ on ‘DOMWindow’: The target origin provided (‘https://aaa.com’) does not match the recipient window’s origin (‘https://bbb.com’).

  • 解决方法:在postMessage 方法里添加参数 “*”(假如没有安全性要求不高的话)
  • 参考:https://stackoverflow.com/questions/27573017/failed-to-execute-postmessage-on-domwindow-https-www-youtube-com-http

参考

  • window.postMessage:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值