HTML5提出了一个新的用来跨域传值的方法,即postMessage(这个名字太通俗了因此你最好看看是否是本身写过一个同名的把它覆盖了)。幸运的是IE8就开始支持了。javascript
咱们假设有两个网站,1.com与2.com,我在1.com的页面上经过iframe或window.open或超连接打开了一个2.com的网页,此时我要在2.com上作操做的时候,给1.com传值,让1.com有所变化。这个过程就是个跨域的过程。html
若是你对window.open熟,你就会知道经过window.open打开的网页(咱们称之为子网页),能够经过window.opener对象,访问到把它打开的页面(父网页),这样一来,调用父页面的函数就是很是简单的事了。可是,在跨域的条件下,window.opener就成了一个空对象,“没有权限”,浏览器会这么告诉你。java
好比,你的父页面有个函数叫callback,而后你子页面本能够这样调用:window.opener.callback(),同域时能成功,跨域时就没有权限了。json
可是,此时你调用window.opener.postMessage(),却能够成功!跨域
关于跨域传值的痛苦我就很少说了,本文只说一些前两天学习postMessage时了解到的重要知识点。数组
window.postMessage(msg,targetOrigin)浏览器 |
这里我要专门说一下postMessage要经过window对象调用!由于这里的window不仅是当前window,大部分使用postMessage的时候,都不是本页面的window,而是其余网页的window!如:安全
1,iframe的contentWindow框架
2,经过window.open方法打开的新窗口的windowdom
3,window.opener
若是你使用postMessage时没有带window,那么,固然,你就是用的本页面的window来调用了它。
这就是要传递的消息了。它能够是一切javascript参数,如字符串,数字,对象,数组,而不是和json同样只局限于字符串,很强大吧?
这个参数称做“目标域”,注意啦,是目标域不是本域!好比,你想在2.com的网页上往1.com网页上传消息,那么这个参数就是“http://1.com/”,而不是2.com.
另外,一个完整的域包括:
协议,主机名,端口号。如:http://g.cn:80/
要对postMessage传来的消息进行处理,就要在页面上加一个onmessage事件。如:
1 2 3 4 |
window.addEventListener('message',function(e) { console.log(e.origin,e.data) ; alert('有数据传来了!') ; }) |
要注意:最好是经过addEventListener或attachEvent来加入onmessage事件,而不要直接window.onmessage=function(){},由于有的浏览器这样加会识别不了(如低版Firefox)
这个onmessage事件接受一个参数,就是代码里的e,实际上他就是一个event对象。但他里面有很明显的3个参数与其余event对象不同,即:
1,data:顾名思义,是传递来的message
2,source:发送消息的窗口对象
3,origin:发送消息窗口的源(协议+主机+端口号).好比从2.com往1.com发了消息,那么1.com收到消息时,e.origin就是2.com
最重要的就是data了,你能够用e.data取得他,而后作后续操做了。不过为了安全,你最好先判断一下e.source和e.origin是否是正确来源,再做操做。
接着刚才的例子来,我着重讲一个弹窗给父页面传消息的例子。
咱们的父页面叫1.com,他上面有关键代码是:
1 2 3 4 |
window.addEventListener('message',function(e) { console.log(e.origin,e.data) ; alert('子页面有数据传来了!') ; }) |
就这么简单。而弹出窗口(2.com)上的代码是:
1 2 |
vardomain='http://1.com/' ; window.opener.postMessage({obj:'I am a obj'},domain ) |
仍是很简单吧!你看,跨域时原本不能访问的window.opener能够访问了——不过你直接调用父页面的方法仍是会失败!就是这么不讲理。
1,必需要说明:经过超连接打开的新窗口也能用window.opener来访问其父页面,代码跟上面同样
2,iframe的例子
父页面:
1 2 |
varo=document.getElementsByTagName('iframe')[0] ; o.contentWindow.postMessage('Hello World',"*");//向框架页传消息 |
被框架包裹的子页面:
1 2 3 4 5 6 7 8 9 |
window.addEventListener('onmessage',function(e) { if(e.domain=='1.com') { if(e.data=='Hello World') { e.source.postMessage('Hello',"*"); //反过来向父页面传消息 }else { alert(e.data) ; } } }); |
这个例子充分说明了postMessage是双向的。
3,window.open一个窗口,而后向他传消息
父页面:
1 2 3 4 5 |
vardomain2='http://2.com/' ; varwin=window.open(domain2+'Portal/2.com.html','wwwwwwww' ) setTimeout(function() { win.postMessage('ddddddddd',domain2 ) },2000) |
子页面:
1 2 3 |
window.addEventListener('message',function(e) { console.log(e.origin,e.data ) }) |
要注意父页面中的setTimeout,也就是要延迟传消息,由于子页面不可能瞬间加载完成,他的onmessage事件也就没初始化成功,这时给他传消息,固然是收不到的了。
1,IE8+虽然支持postMessage,但只支持iframe的方式,window.open打开的新窗口之间,无法用。直到IE10才有相关改进
2,如何在本地模拟跨域呢?在hosts文件里加入:
127.0.0.1 1.com127.0.0.1 2.com
就能够模拟出2个不一样的域名了。