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就成了一個空對象,「沒有權限」,瀏覽器會這麼告訴你。html5
好比,你的父頁面有個函數叫callback,而後你子頁面本能夠這樣調用:window.opener.callback(),同域時能成功,跨域時就沒有權限了。java
可是,此時你調用window.opener.postMessage(),卻能夠成功!json
關於跨域傳值的痛苦我就很少說了,本文只說一些前兩天學習postMessage時瞭解到的重要知識點。跨域
window.postMessage(msg,targetOrigin)數組 |
這裏我要專門說一下postMessage要經過window對象調用!由於這裏的window不僅是當前window,大部分使用postMessage的時候,都不是本頁面的window,而是其餘網頁的window!如:瀏覽器
1,iframe的contentWindow安全
2,經過window.open方法打開的新窗口的windowapp
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個不一樣的域名了。
參照信息:
HTML5 postMessage 和 onmessage API 詳細應用
http://msdn.microsoft.com/en-us/library/ie/cc197015(v=vs.85).aspx
http://stackoverflow.com/questions/16226924/is-cross-origin-postmessage-broken-in-ie10
https://developer.mozilla.org/zh-CN/docs/Web/API/Window.postMessage