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

相关文章
相关标签/搜索