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

來源:互聯網
上載者:User

有關跨域通訊,可以叫跨域請求,跨域資料訪問,想必大家在工作或多或少地接觸到,網上也能搜出一大羅出來。我的解決方案與他們的不同之處是不使用代理頁。

確切來說,在IE67無法使用postMessage的情況,我們通常需要動態產生一個隱藏iframe來載入通訊頁,而它可能是跨域的。window.name的逆天之處在於,iframe.contentWindow.name是共用,即便因為URL的切換導致裡面的不斷改變,如果沒有人為修改它,一直就是那個樣子。但不同域的情況下,我們仍然不能訪問iframe中的window.name,這時我們再把iframe切換成本域的頁面就行了。這就是window.name通訊的實現機制。

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

下面是我的實現:

//by 司徒正美 2010 7 30                (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://www.cnblogs.com/rubylouvre/archive/2012/07/28/2613565.html",function(a){                        window.console &&  console.log(a+"!!!!!!!!!!!!!")                    })                })();

現場執行個體觀摩:資料請求頁,資料發送頁,具體代碼見頁面源碼!然後我們就會在資料請求頁的控制台看到列印日誌了!

再說回來,為什麼叫做UIloader呢,因為一般的跨域資料傳送,使用JSONP就夠了,非常輕便!但對於UI組件,比如grid,它通常包括一個體積也夠為嚇人的JS檔案,還有一個樣式表,如果不想通過字串拼接來渲染介面,我們還可能用到前端模板,當然還有圖片什麼的。撇開圖片不談,JS,前端模板,樣式我們都可以統統整到一個JS檔案裡面的,但會顯然很亂,尤其是大段的CSS樣式,HTML欄位,這是不是用HTML來放置它們比較好呢。我們用一個HTML來放置它們,樣式表寫到style標籤中,HTML寫到一個DIV上,指令碼寫到一個script中。那麼它們它們拼成一個對象:

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變成對象!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.