1、背景 html
在这个Web页面愈来愈丰富的时代,页面经过iframe嵌入其余的页面也愈来愈常见。但因为浏览器同源策略的限制,不一样域之间属性和操做是没法直接交互的,因此在这个时候,开发者多多少少须要一些方案来突破这些限制。跨域问题涉及的地方也不少,如文档之间的消息通讯、ajax请求、Cookie等,本文讨论的是iframe和父页面的消息通讯。 git
2、现状 github
目前网上也能够找到各类解决方案(少说都有10+个,有兴趣的话能够去看看),对于现代浏览器来讲,原生的postMessage API必定是不二的选择,因此各类方案的不一样点均在于IE 六、7中的处理(不用兼容IE六、7的同志能够去看其余文章了)。固然这么多方案有各类优缺点,甚至有些只支持单向跨域,我的以为实际意义不大。另一些方案须要proxy.html这样的代理页面作中转,可是涉及服务器上的部署,而且对于多方合做来讲仍是有些麻烦。 web
3、思路 ajax
虽然再也不复述现有的各类方案,但仍是想交待一点上下文。相信网上看到最多方案就是利用location.hash或是window.name进行iframe的跨域通讯: 跨域
讲到这思路也比较清晰了,我们就用window.name呗,但问题又来了:只有两个页面同域时才能访问window.name。这个问题还好,只要把iframe改成与父页面同域就能够了。这又衍生了新的问题:这不是意味着只能单向通讯了吗,iframe怎么向父页面发消息(不可能去改父页面的location吧)?在暗骂坑爹的同时偶然发现了一个很神奇的方法,就是想访问一个iframe的window.name时,只要将其location改成‘about:blank’便可,屡试不爽~没错这个“特性”能够视为IE6/7的一项安全性问题,但利用这个特性来进行跨域通讯并无实际的安全风险。 浏览器
具体的实现见下图,在iframe的内部再建立一个iframe(咱们称之为信使),父子页面轮询信使的window.name,父子页面各自使用变量保存window.name,轮询时发现有变化即被视为收到消息。基本原理就是这么简单,咱们继续.. 安全
图1 服务器
做为一个通用的解决方案,咱们的目标是提供一个js文件,封装通讯的接口,须要通讯的页面只要加载js文件就行。但在封装前,须要考虑更复杂一点的状况:当父子页面双方频率较高地双向通讯时,如何进行支持?按照上述的方案,信使的window.name并无读写锁的概念,这意味着消息很容易乱掉或被漏掉。因此更好的方案应该是:建立两个信使,分别负责”父–>子”和”子–>父”的消息传递,而且为了防止消息被冲掉,发送消息时会维护一个消息队列,在取消息时处理消息队列里的全部消息。见图2。 dom
图2
4、封装
最后的封装就是加入了postMessage API的检测,另外也要判断是否为跨域,这样就知足了全部iframe通讯的状况了。这里实现的信使只负责消息的监听和发送,因此在使用上是很是简单的:
JavaScript
// 父页面中 // 初始化信使, 告知与其交互的iframe引用 var messenger = Messenger.initInParent(iframeEl); // 监听消息 messenger.onmessage = function (data) { ... }; // 发送消息 messenger.send(message);
// iframe中 // 初始化信使 var messenger = Messenger.initInIframe(); // 监听消息 messenger.onmessage = function (data) { ... }; // 发送消息 messenger.send(message);
|
|
具体使用能够参考下方的demo : )
5、总结
虽然国内也有人提过使用”about:blank”进行iframe通讯的,可是代码的封装和可读性都不是太好,本方案是一日本人所提出,我以为处理的很好,因此就拿出来和你们分享下。虽然尝试过优化轮询那一块,但暂时无果,有兴趣的朋友能够一块儿研究下~
DEMO:点击这里