多个浏览器窗口之间通信

文章介绍了在项目开发中如何使用window.open和window.openerAPI实现同源浏览器间的通信,创建ScreenWin类来管理屏幕信息。当遇到不同源浏览器通信需求时,可以使用WebSocket或postMessage方法。此外,还讨论了刷新浏览器时如何维护通信通道和使用localStorage进行简单通信。
摘要由CSDN通过智能技术生成

前言

在项目开发的过程中,第一次遇到了双浏览器之间需要通信的需求,通过查阅各种方法发现各位大佬的实现方法对于目前的项目而言,都不是特别合适。

最后通过查阅MDN(window)得到了灵感,通过window.openwindow.opener两个API简单实现了浏览器之间的通信。但是目前这个方法只支持同源的浏览器之前通信,如果想要不同源之间的浏览器通信则需要使用其他方法。

建立通信通道

  1. 新建一个class 用于存储各个屏幕的信息,这里可以根据个人的需求做调整


//利用 window.open 和 window.opener 简单解决双屏通信问题
class ScreenWin {
  constructor(name, screenWins, getMesCallBack) {
    this.name = name; //当前浏览器名称
    // 数据类型使用Object name-ScreenWin的一个实例
    this.screenWins = screenWins; //两个浏览器时使用
    // this.setScreenWins(screenWins);
    //接受消息后的回调函数
    this.getMesCallBack = getMesCallBack;
  }
  // 多个浏览器时使用这个 
  setScreenWins(screen) {
    this.screenWins = screen; //{XXX:ScreenWin}
    for (const key in screen) {
      if (Object.hasOwnProperty.call(screen, key)) {
        let screenWin = screen[key].screenWins; //{XXX:ScreenWin}
        for (const key in screenWin) {
          if (Object.hasOwnProperty.call(screenWin, key)) {
            const element = screenWin[key]; //{XXX:ScreenWin}
            if (key != this.name) {
              this.screenWins[key] = element || this.screenWins[key];
            }
          }
        }
      }
    }
  }
  //接收到更新信息
  UpdateScreenWin(name, screenWin) {
    this.screenWins[name] = screenWin;
  }
  //通知各位 我这里面需要更新
  sendUpdateScreenWin(name) {
    for (const key in this.screenWins) {
      if (Object.hasOwnProperty.call(this.screenWins, key)) {
        this.screenWins[key]?.UpdateScreenWin(name, this);
      }
    }
  }
  //关闭窗口 根据需求可以重写此方法
  closeScreen() {
    this.senMessages({ key: "close" });
  }
  //批量发送消息
  senMessages(mes) {
    for (const key in this.screenWins) {
      if (Object.hasOwnProperty.call(this.screenWins, key)) {
        this.senMessage(key, mes);
      }
    }
  }
  //单个屏幕发送消息
  senMessage(name, mes) {
    this.screenWins[name] && this.screenWins[name].getMessage(mes);
  }

  getMessage(mes) {
    this.getMesCallBack(mes);
  }
}
  1. 利用window.open打开新的浏览器,同时建立单个通道

  • mainScreen 浏览器打开 otherScreen浏览器的操作


//mainScreen 浏览器打开 otherWin浏览器的操作
let otherScreen = window.open("https://XXXX", "openName");
window.screenWin = new ScreenWin(
  "mainScreen", //当前浏览器名称 多个浏览器时候注意名称不可重复
  {
    otherScreen: otherScreen.screenWin, //打开的新的浏览的ScreenWin的实例
  },
  handleMesCallBack //接受消息的回调函数
);
  • otherScreen 被打开的操作,需要通知其他浏览器我当前刚刚被打开。


let mainScreen = window.opener;
window.screenWin = new ScreenWin(
  "otherScreen", //当前浏览器名称 多个浏览器时候注意名称不可重复
  {
    mainScreen: mainScreen.screenWin, //打开的新的浏览的ScreenWin的实例
  },
  handleMesCallBack //接受消息的回调函数
);
//通知其浏览器需要更新自己的ScreenWin实例
window.screenWin.UpdateScreenWin("otherScreen"); 

这个时候 mainScreen和otherScreen两个浏览器之间就建立好了通道(ScreenWin的实例)。可以通过senMessages、senMessage方法传递信息,通过handleMesCallBack接受信息。

刷新浏览器需要更新通道

  • mainScreen 刷新的时候会丢失window.screenWin

  • 如何判断浏览器是刷新还是关闭

  1. mainScreen浏览器刷新,通过window.onunload以及window.onload之间的时间差判断浏览器是刷新还是关闭(目前似乎只有这个唯一的办法去判断浏览器的刷新还是关闭,如果有其他比较好的方法欢迎评论)。

  1. mainScreen刷新会丢失window.screenWin这个问题需要在mainScreen再次打开的时候利用 window.open再次拿到otherScreen的screenWin,同时重新赋值window.screenWin。


//关闭浏览器的时候 记录otherWindHash打开的地址
window.onunload = () => {
  sessionStorage.setItem("otherWindHash", otherScreen?.location?.hash);
};
//打开浏览器的时候 拿到otherWindHash的地址
window.onload = () => {
  otherScreen = window.open(sessionStorage.getItem("otherWindHash") || "默认地址", "openName");
  window.screenWin = new ScreenWin(
    "mainScreen",
    {otherScreen: otherScreen.screenWin},
    handleMesCallBack //接受消息的回调函数
  );
  //通知otherWindHash更新新信息
  window.screenWin.sendUpdateScreenWin("mainScreen");
};
  • otherScreen刷新


window.screenWin = new ScreenWin(
  "otherScreen",
  { mainScreen: window.opener.screenWin },
  handleMesSub
);
window.screenWin.sendUpdateScreenWin("otherScreen");

以上就建立了两个及以上的浏览器通信通道handleMesCallBack方法接收到不同信息就可以各自处理了。

其他通信方法

如果是非同源的浏览器之间的相互通信,可以通过WebSocket、postMessage等方法。

同源浏览器之间还可以使用localStorage通信,localStorage通信就是每个浏览器监听localStorage的变化来进行通信。如果是只有很少的通信需求不想麻烦用localStorage也是挺好的。


window.addEventListener("storage", ListenerMethod);
ListenerMethod = (e)=>{
 if(e.key=='XXX'){//XXX消息变化之后做出响应}
}
//关闭监听
window.removeEventListener("storage", ListenerMethod);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值