zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    django系列6--Ajax03 ajax参数
    django系列6--Ajax06 使用插件,Sweet-Alert插件
    django系列6--Ajax05 请求头ContentType, 使用Ajax上传文件
    django系列6--Ajax04 请求设置(设置csrf_token)
    django系列6--Ajax01 特点, 基本格式, 向前端发送数据
    django系列4.2--自定义标签, 自定义过滤器, inclusion_tag, 引入静态文件(css,js等)
    面向对象之封装之如何隐藏属性, 封装的底层原理
    面向对象之------多态与多态性
    在子派生的新方法中重用父类功能的两种方式
    菱形继承
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2615280.html
Copyright © 2011-2022 走看看