postmessage封装跨域消息传递

1 篇文章 0 订阅

第一部分 postMessage消息传递

CD.html

<div style="width:200px; float:left; margin-right:200px;border:solid 1px #333;">
    <div id="color">Frame Color</div>
</div>
<div>
    <iframe id="child" src="CD2.html"></iframe>
</div>

CD.js

// 通过window获取iframe
// window.frames是个伪数组,可以通过window.frames[index]或window.frames[name]来获取
window.function(){
    window.frames[0].postMessage('getcolor','*');
    window.addEventListener('message',function(e){
        var color=e.data;
        document.getElementById('color').style.backgroundColor=color;
    },false);
}

CD2.js

window.addEventListener('message',function(e){
    if(e.source!=window.parent) return;
    var color=$('body').css('background-color');
    window.parent.postMessage(color,'*');
},false);

详细解读:postMessage(data,origin)
一、 参数
1.data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。

2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
二、 接收消息
监听window的message事件就可以

window.addEventListener('message',function(e){
    if(e.source!=window.parent) return;
    var color=$('body').css('background-color');
    window.parent.postMessage(color,'*');
},false);

e有几个重要属性:
data:顾名思义,是传递来的message(数据、消息)
source:发送消息的窗口对象
origin:发送消息窗口的源(协议+主机+端口号)

三、 使用场景
1.页面和其打开的新窗口的数据传递
2.多窗口之间消息传递
3.页面与嵌套的iframe消息传递
4.上面三个问题的跨域数据传递
tips:iframe引入的页面,可以相互通信;window.open打开的页面只能父页面向子页面发消息

第二部分:封装

	/**
 * 跨域js
 */
(function(window){
   var CD = function(){
   };
   CD.prototype = {
      version : "0.0.1",
      component : {},
      components : {},
      interfaces : {},
      /**
      * 初使化
      */
      init : function(){
         this.component = {
            type : this.isMaster()? "MASTER" : "SLAVE" ,
            name : this.isMaster()? "MASTER" : window.name ,
            url : window.location.host,
            port : window.location.port || 80
         };
         if(!this.component.name){
            throw new Error("Error iframe must has a name");
         };
         //this.components[this.component.name] = this.component;
         this.register(this.component);
         this.extends("register" ,function(data){
            this.components[data.component.name] = data.component;
         });
      },
      /**
      * 是否是Master
      * 如果窗口为顶层窗口则认为是Master
      */
      isMaster :function(){
         return window === window.top;
      },
      /**
      * Salve将自身组件注册到MASTER端
      */
      register : function(){
         this.send("MASTER" , "register" ,{info:"i'm coming register!", component:this.component});
      },
      /**
      * 扩展接口方法
      * @param {String} name接口名称
      * @param {Function} fun 接口方法
      */
      extends : function(name,fun){
         this.interfaces[name] = fun;
      },
      /**
      * 打印跨域日志的方法
     *
     * @param {Object} mesg 要打印跨域消息的内容
     */
       log : function( mesg){
         if (!window.console || typeof window.console === 'undefined')
            return;
         window.console.log("["+new Date()+"]["+this.version+"]["+this.component.type+"]["+this.component.name+"]["+mesg.type+"][" + window.JSON.stringify(mesg)+"]");
       },
       /**
       * 发送信息到其它组件 - html5原生态方法包装
       *
       * @param {Window} targetWindow目标系统window对象
       * @param {String} targetUrl目标系统 URL
       * @param {Object} mesg 对象
       */
       postMessage : function(targetWindow, targetUrl, mesg){
         this.log(mesg);
         targetWindow.postMessage(JSON.stringify(mesg), targetUrl);
       },
       /**
       * 发送消息方法
       * @param {String} componentName组件名称
      * @param {String} method接口名称
     * @param {Object} data数据
      * @param {Function} callback回调
     */
       send : function(componentName,method,data,callback,type){
         if(this.isMaster() && componentName ==="MASTER")
            return;
         var source = this.component.name;
         var mesg = {
            source : source,
            target : componentName,
            method : method,
            data : data,
            type : type || "REQUEST"
         };
         if(callback)
            this.extends(method+"Callback" , callback) ;
         var w = this.isMaster()? window.document[componentName] : window.top;
         var host = this.isMaster()? this.components[componentName].host : "*";
         //console.info(host);
         this.postMessage(w, "*", mesg);
       },
       /**
       * 处理接收到的其它系统的请求跨域请求
       *
       * @param {Event} event事件对象
       */
       process : function(event) {
         var mesg = JSON.parse(event.data);
         //console.log(event);
         this.log(mesg);
         var interface1 = this.interfaces[mesg.method];
         var result ;
         if(interface1){
           result = interface1.call(this,mesg.data);
         }else{
            throw new Error("["+this.component.name+"] not have interface:[" + mesg.method + "]");
         }
         if(result){
            this.send(mesg.source, mesg.method + "Callback", result, null,"RETURN");
         }
       },
       /**
       * 绑定窗口事件,用于监听跨域事件
       */
       listen : function(){
         if (window.addEventListener) {// 非IE
            window.addEventListener("message", function(event){
               window.CD.process(event);
            }, false);
         } else {// IE
            window.attachEvent("onmessage", function(event){
               window.CD.process(event);
            });
         }
      }
   };
   window.CD = new CD();
   window.CD.init();
   window.CD.listen();
})(window);

第三部分 使用

A.	父窗口iframe组件传递消息
CD.send('custom_frame_'+$scope.components[$scope.signIndex].code, 'SEND_PING_AN_YUN_INFO', args, function () {
});

参数1:目标iframe的名字
参数2:事件名(根据这个名字获取数据)
参数3:数据
回调函数:执行完执行

B. 对应iframe接收消息

CD.extends('SEND_PING_AN_YUN_INFO', function (result) {})

A1:iframe组件向父窗口发送消息

	CD.send('MASTER','COME_FROM_COMPONENTS_EVENTS',{}, function(data) {
    console.log('OPEN_PHONE_CURR_OPERATE:',data);
});

B1:父窗口接收对应组件消息

CD.extends('COME_FROM_COMPONENTS_EVENTS',function(args){
    $scope.showComponent($scope.signIndex);
});

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值