跨源通信--Window.postMessage()

2,396 阅读2分钟

这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

大家好,我叫小杜杜,相信各位小伙伴对跨域都了解一些,那么你知道跨源吗?献给大家说一个标签,不知道有没有小伙伴用,那就是iframe标签,这个标签的作用是嵌套其他页面,而主页面和嵌套的页面要想通信,就是跨源通信~

跨源通信

跨源通信:通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机  (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。

从广义上讲,一个窗口可以获得对另一个窗口的引用(比如 targetWindow = window.opener),然后在窗口上调用 targetWindow.postMessage() 方法分发一个  MessageEvent 消息。接收消息的窗口可以根据需要自由处理此事件 (en-US)

window.postMessage()可以安全的实现跨源通信

postMessage 的语法

语法:otherWindow.postMessage(message, targetOrigin, [transfer]);

  • otherWindow: 其他窗口(目标窗口)的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames(如父窗口向内嵌的iframe窗口发送信息)

  • message :信息内容,低版本浏览器只支持字符串,高版本可以各种数据都行

  • targetOrigin :目标窗口的源,可以是字符串*表示无限制,或URI,需要协议端口号和主机都匹配才会发送

  • transfer:可选,是一串和message 同时传递的 Transferable对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。

兼容性

image.png

MessageEvent

MessageEvent:  是接口代表一段被目标对象接收的消息。

如:

    window.addEventListener("message", function(MessageEvent){ 
        var origin = event.origin || event.originalEvent.origin; 
        .... 
     }, false);

四个属性:

  • messag:类型
  • data:window.postMessage的第一个参数
  • origin:调用postMessage时页面的当前状态
  • source:调用postMessage的窗口信息

示例

通过iframe嵌套父子窗口进行通信

  • 父窗口
    <!--我是父窗口-->  
    <div class="parent" >
          <iframe src="子窗口链接" id="iframe"></iframe>
    </div>
    <script>
    //监听子窗口信息
     window.addEventListener('message',function(event){
       ...
       })
    //父窗口给子窗口发消息,
    document.getElementByID('iframe').contentWindow.postMessage(msg,'子窗口源');
    </script>
  • 子窗口
    <!--我是子窗口-->  
    <div class="child"></div>
    <script>
    //子窗口给父窗口发消息
    try {//放到trycatch里面,解决有些手机卡住报错问题
      window.top.postMessage(msg,'父窗口源');
          //嵌套一层使用window.top(parent),多层window.frameElement
          //使用top而不是window,top指向iframe最顶层窗口
      } catch (error) {
    }

    //监听父窗口信息
     window.addEventListener('message',function(event){
       ...
       })
    </script>

注意:

  • 父窗口给子窗口发信息,需要用iframecontentWindow属性作为调用主体
  • 子窗口给父窗口发的信息需要使用window.top,多层iframe使用window.frameElement

End

个人认为iframe这个标签非常🤮,因为我人生中的第一个通宵就在这个标签上,建议能不用就不要用,因为这个确实很🤮,但你至少要了解下,方便以后多一种选择,喜欢的点个赞👍🏻支持下吧(● ̄(エ) ̄●)