window.name + postMessage實現不用代理頁的跨域通訊

在IE67沒法使用postMessage的狀況,咱們一般須要動態生成一個隱藏iframe來加載通訊頁,而它多是跨域的。window.name的逆天之處在於,iframe.contentWindow.name是共用,即使由於URL的切換致使裏面的不斷改變,若是沒有人爲修改它,一直就是那個樣子。但不一樣域的狀況下,咱們仍然不能訪問iframe中的window.name,這時咱們再把iframe切換成本域的頁面就好了。這就是window.name通訊的實現機制。

雖然說生成一個代理頁沒什麼難度,更況且它能夠是空白的頁面。但做爲一個組件,這也算是一種約束。約束越少越好。經我研究,有兩個URL能夠算是本域的永久地址,一個是/favicon.ico(IE下不行),另外一個是about:blank。咱們就用about:blank做爲代理頁!css

下面是實現:html

(function() { 前端

  
                     //數據發送頁的URL,回調,加用於opera的延時時間(可選)
                     var UIloader = function ( url, callback, operatime){
                         if ( typeof url === "string" && typeof callback == "function" ){
                             url += (url.indexOf( '?' ) > 0 ? '&' : '?' ) + '_time' + new Date * 1;
                             operatime = typeof operatime === "number" ? operatime  : 3000;
                             var el = document.createElement( 'iframe' ), data;
                             function receive(e){
                                 e = e || event;
                                 el._state = 2;
                                 callback(e.data)
                                 if (window.removeEventListener){
                                     window.addEventListener( 'message' , receive, false )
                                 } else {
                                     window.detachEvent( 'onmessage' , receive);
                                 }
                                 body.removeChild(el)
                             }
                             if (window.addEventListener ){
                                 window.addEventListener( 'message' , receive, false )
                             } else {
                                 window.attachEvent( 'onmessage' , receive);
                             }
                             el.style.display = "none" ;
                             el._state = 0;
                             var body = document.body || document.documentElement;
                             body.insertBefore( el, body.firstChild );
                             ;( function ( node, type, fn ) {
                                 if ( window.VBArray ) {
                                     node.attachEvent( 'on' + type, fn);
                                 } else {
                                     node.addEventListener(type, fn, false );
                                 }
                             })(el, 'load' , function eee() {
                                 if (el._state === 1 ) {
                                     try {
                                         data = el.contentWindow.name;
                                     } catch (e) {}
                                     el._state = 2;
                                     callback(data)
                                     callback = function (){}
                                     body.removeChild(el)
                                 } else if (el._state === 0) {
                                     setTimeout( function (){
                                         el._state = 1;
                                         el.contentWindow.location.replace( "about:blank" )
                                     }, (window.opera ? operatime : 31) ) //必須等iframe的資源都加載完才跳轉,opera顯然load觸發時機不對
                                 }
                             });
                             el.src = url;
                         } else {
                             throw "arguments error"
                         }
                     }
  
                     UIloader( http://my.oschina.net/u/248095 ,function(a ){
                         window.console &&  console.log(a+ "!!!!!!!!!!!!!" )
                     })
                 })();

現場實例觀摩:數據請求頁數據發送頁,具體代碼見頁面源碼!而後咱們就會在數據請求頁的控制檯看到打印日誌了!node

再說回來,爲何叫作UIloader呢,由於通常的跨域數據傳送,使用JSONP就夠了,很是輕便!但對於UI組件,好比grid,它一般包括一個體積也夠爲嚇人的JS文件,還有一個樣式表,若是不想經過字符串拼接來渲染界面,咱們還可能用到前端模板,固然還有圖片什麼的。撇開圖片不談,JS,前端模板,樣式咱們均可以通通整到一個JS文件裏面的,但會顯然很亂,尤爲是大段的CSS樣式,HTML字段,這是否是用HTML來放置它們比較好呢。咱們用一個HTML來放置它們,樣式表寫到style標籤中,HTML寫到一個DIV上,腳本寫到一個script中。那麼它們它們拼成一個對象:git

var data = {
    html: div.innerHTML,
    js: script.text,
    css: style.cssText
}
  
   window.name = data
      
    if (window.postMessage){
       window.parent.postMessage(data, "*" );
    }

不過須要注意的是postMessage在IE下只能傳字符串,咱們只好在發送頁統一返回字符串,用JSON.stringify轉換一下就好了,取回來再用JSON.parse變成對象!github

相關文章
相關標籤/搜索