首先回顾一下什么是同源策略
同源策略
- 协议(通常为https)
- 端口号(443为https的默认值)
- 主机 (两个页面的模数 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对象的引用:
-
window.open
/window.opener
使用window.open返回的对象 -
HTMLIFrameElement.contentWindow
iframe元素的contentWindow属性 -
window.parent
当前窗口的父窗口对象,如果没有返回自身 -
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: