记录自己在遇到JS父子框架跨域通讯问题的解决.

原来我博客就一个域名,后面换成多域名了.

 

我现在登陆时单独一个域名.

博客主域名: www.getce.cn

博客登陆域名:  login.getce.cn

 

所以交互的时候要扯到跨域的问题.

 

 

不跨域通讯

 

原来不跨越非常简单.

 

子框架访问父框架

 

// 访问父框架变量,
// 或者window.parent.user .
// parent上一级,top就是最顶级.

console.log(window.top.user);


//调用父框架的函数
window.top.abc();

 

父框架访问子框架

 

 

sub_window = window.frames["sub_id"];   //获得window对象

//用法
sub_window.document.body.innerHTML //获取子框架源码
sub_window.test();  //调用子框架中test函数.

 

 

跨域通讯

 

网上最常见的方案就是设置document.domain 但是我实际测试没效果....

 

于是我用了postMessage 消息机制通讯. 这可能是win api抄过来的概念....

 

postMessage不但可以用于跨域,不跨域也可以.

 

注册监听函数


//回调函数
function receiveMessage(event){
  //event就是另外窗口传过来的. 支持数组,对象,还有基本变量类型.
}

window.addEventListener("message", receiveMessage, false);

如果双向通讯那么子父框架都需要自己都注册监听.

当收到消息会自动进入回调函数,

 

 

发送消息

 

子框架向父框架发送字符串.

window.parent.postMessage("hi","https://www.getce.cn");

 

window.parent  就是父窗口的window对象.

第二个参数的域名就是父框架的域名,带协议.

 

 

反过来也是.

父框架给子框架发,给兄弟框架发也是.

先获取window对象.然后接postMessage.

sub_window = window.frames["sub_id"]; 
sub_window.postMessage("ok","https://login.getce.cn");

 

第一个参数是  需要传递的变量或者对象,或者数组.

第二个参数是 对方的带协议的域名.

 

 

处理消息

 

 

  function receiveMessage(event)
  {
    console.log('接到站点的消息:');
    console.log(event.origin);  //控制台打印 来自哪个域名发来的消息.
    //判断是否是自己子框架发来的,如果不是就不处理.

    if (event.origin.indexOf("getce.cn") == -1){
      return;
    }

   console.log(event.source);   //来源页面
   console.log(event.data);  //发送过来的数据
   
   //如果发来的是字符串"ok",那么返回一个 hi.
   //直接可以用event.source发消息.直接回复.
   if (event.data == "ok"){
     event.source.postMessage("hi","https://login.getce.cn");
   }

}

 

取消监听

 

window.removeEventListener("message", receiveMessage, false);

 

 

 

实际应用

 

本博客博文下面的登陆就是.

如果没有登陆的话,任意博文下面,

编辑框有个登陆按钮.

点登陆实际上打开了一个跨域的登陆页面.

 

此时父框架监听子框架消息(因为需求简单,只需要单向通讯)

用户登陆后,站点是有cookie的.但是父框架如果不刷新,或者不处理,是无法知道已经登陆的.

这时候,子框架(登陆页面)将用户信息传给父框架,那么父接收用户信息后就知道已经登陆了.即可免刷新登陆.