好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

window.name + postMessage实现不用代理页的跨域通信

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作为代理页!

下面是我的实现:

//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变成对象!

 

 

标签:  javascript

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于window.name + postMessage实现不用代理页的跨域通信的详细内容...

  阅读:46次