iframe通过postMessage跨域通信

5,708 阅读2分钟

首先回顾一下什么是同源策略

同源策略

  1. 协议(通常为https)
  2. 端口号(443为https的默认值)
  3. 主机 (两个页面的模数 Document.domain设置为相同的值)

提到iframe有很多人嗤之以鼻,iframe的缺点很多,但是在某些特定场景下,也可以发挥不错的作用,首先看一下iframe的缺点:

iframe缺点以及解决方案

缺点:

1.iframe会阻塞主页面的Onload事件;

2.相同域iframe和主页面共享http连接池,所以如果相同域用多个iframe会阻塞加载

解决方案:

动态生成iframe,在主页面加载完成后去生产iframe加载,从而避免阻塞的影响

3.iframe 对SEO不友好

在广告位以及内部系统等适合的场景中使用iframe

iframe跨域通信

postMessage

API简介
otherWindow.postMessage(message, targetOrigin, [transfer]);

otherWindow是window对象的引用:

  1. window.open/window.opener 使用window.open返回的对象

  2. HTMLIFrameElement.contentWindow iframe元素的contentWindow属性

  3. window.parent 当前窗口的父窗口对象,如果没有返回自身

  4. window.frames 当前窗口的所有直接子窗口

看起来比较复杂,如果想实现主页面和iframe交互,只需要第二项和第三项

targetOrigin

1.*代表可以发送到任意origin

2.https:www.xxx.com:443可以指定特定的origin发送,默认端口号可以省略

使用

以主页面中嵌套一个iframe为案例说明

主页面:

  //html
  <iframe src="./iframe.html" id="iframe" frameborder="0" scrolling="no" width="100%"></iframe>
//js
//发送message
var iframe = document.getElementById('iframe')
iframe.contentWindow.postMessage(data, '*')

子页面:

//js
//监听message事件
window.addEventListener("message", receiveMessageFromIndex, false);//注意ie中事件绑定是attachEvent
//回调函数
function receiveMessageFromIndex(event) {
//传递的data可以从event.data中获取到
}
//发送消息给主页面
window.parent.postMessage(data, '*');
//主页面监听方式和子页面一样

这样就比较简单的实现了主页面和子页面的双向通信。

兼容性

需要注意的是postMessage API中的message在ie8/ie9等一些低版本浏览器中,中是不支持除String以外的其他类型时(因为不支持结构化克隆算法),所以,如果要兼容低版本ie,需要通过JSON.strigify以及JSON.parse去发送和接受。

这里给了一个主页面以及子页面的双向通信的demo:

演示地址

仓库地址