浏览器tab页面之间的通讯

浏览器多标签页之间通讯的方法

前提

  • 业务场景:A 标签页打开B 标签页后,A 需要根据 B 执行某些操作后的信息进行其他操作(比如重新获取信息)
  • 重要概念
    • 同源:两个页面的协议端口主机都相同

通讯方法

window.localstorage

  • 用法

    • A 标签页: 监听storage事件
    • B 标签页: 调用localStorage.setItem方法
  • 示例

      // A 页面中
      window.addEventListener("storage", function(event) {
        // 执行其他操作
      })
    
      // B 页面中
      localStorage.setItem(key, value);
    
      // 注意:A 标签页如果调用 localStorage.setItem 是不会触发该页面的 storage 事件的
  • 效果
    localstorage实现效果

  • 兼容
    图片说明

  • 不足:同源限制,不支持跨域

  • 其他

window.postMessage

  • 用法

    • 获取window对象:A 通过 window.open或者iframe获取 Bwindow对象
    • 监听message事件:A, B 窗口都监听message事件,即window.addEventListener("message", function(event) {})
    • 发送消息:A 窗口通过window.postMessage发送消息给 B 窗口
    • 获取发送者的window对象:B 窗口通过message事件可以获取到 A 窗口的window对象a,并且可以利用a发送消息给 A 窗口
    • 通过以上做法,可以实现两个窗口间的通信
  • 示例

      // A 标签页(https://www.baidu.com)
      window.addEventListener("message", function(event) {
          // 对发送过来的消息进行拦截
          // 执行重新获取信息操作
          console.log(event);
      })
    
      var Bwin = window.open("https://i.fkw.com");    // 打开新窗口,并且获取 B 窗口的 window 对象
    
      Bwin.postMessage("hello B, i am from A", "https://www.i.fkw.com");   // 发送消息给 B 窗口
    
      // B 标签页(https://i.fkw.com)
      var Awin = null;    
      window.addEventListener("message", function(event) {
          // 这里进行拦截,并且获取 A 窗口的 window 对象
          var origin = event.origin;
          if(origin === 'https://www.baidu.com') {
              Awin = event.source;
          }
      });
    
      Awin.postMessage("hello A, i am from B", "https://www.baidu.com");
  • 展示
    postMessage实现效果

  • 兼容
    图片说明

  • 好处:支持跨域,推荐

  • 其他

SharedWorker

  • 用法

    • 服务端添加sharedWorker.js,用于客户端创建SharedWorker对象
    • 标签页创建SharedWorker对象:新打开的标签页必须创建SharedWorker对象,才能接收到其他标签页传送的信息
  • 示例

      // sharedWorker.js 文件
      var clients = [];   // 存储每个标签页
      onconnect = function(e) {
        var port = e.ports[0];
        clients.push(port);   
        port.addEventListener('message', function(e) {
          for(var i = 0; i < clients.length; i++) {
            var eElement = clients[i];
            eElement.postMessage(e.data);
          }
        });
        port.start();
      }
    
      // page1 页面 page2 页面基本相同,都是定义一个 sharedWorker 对象
      var myWorker1 = new SharedWorker("./sharedWorker.js");
    
      myWorker1.port.postMessage('i am from page1');
    
      myWorker1.port.onmessage = function(e) {
          var result = e.data;  // 共享推过来的数据
          console.log(result);
      }
  • 展示
    shareWorker实现效果

  • 兼容
    图片说明

  • 不足:只能同源,并且sharedWorker.js文件放在服务端,兼容性一般

  • 其他

BroadcastChannel

  • 用法

      // A.html
      const channel = new BroadcastChannel('tabs')
      channel.onmessage = evt => {
          // evt.data
      }
    
      // B.html
      const channel = new BroadcastChannel('tabs')
      channel.postMessage('hello')
  • 优劣:同源,跟 localStorage 一样,同域,API简单;兼容性一般,ieedge不支持, 不会持久化,较为干净

  • 相关知识

onvisibilitychange 事件

  • 用法
      document.onvisibilitychange = () => { // 页面加载完即调用
          if (document.visibilityState === 'visible') { // 页面是否展示
            // AJAX --> 通过 ajax 向后台获取数据
          }
        }
  • 原理:通过 tab 切换展示事件来获取对应更新的资源
  • 优劣:兼容性ok,API简单
  • 相关知识

EventSource

The EventSource interface is web content's interface to server-sent events. An EventSource instance opens a persistent connection to an HTTP server, which sends events in text/event-stream format. The connection remains open until closed by calling EventSource.close().

  • 用法

      // 前端
        const es = new EventSource('/notification')
    
        es.onmessage = evt => {
          // evt.data
        }
        es.addEventListener('close', () => {
          es.close()
        }, false)
    
        // 后端
        const clients = []
    
        app.get('/notification', (req, res) => {
          res.setHeader('Content-Type', 'text/event-stream')
          clients.push(res)
            req.on('aborted', () => {
              // 清理clients
            })
        })
        app.get('/update', (req, res) => {
          // 广播客户端新的数据
          clients.forEach(client => {
            client.write('data:hello\n\n')
            setTimeout(() => {
              client.write('event:close\ndata:close\n\n')
            }, 500)
          })
          res.status(200).end()
        })
  • 原理:同webSocket,双向通道。

  • 优劣势:实时通讯,跨域,兼容性一般。

  • 相关知识

其他

  • WebSocket也可以实现多标签页之间的通讯,其是HTML5新增的协议,它的目的是在浏览器和服务器之间建立一个不受限的双向通信的通道。比如说,服务器可以在任意时刻发送消息给浏览器,这意味着 B 页面的消息可以由服务器发送给 A页面。
  • Cookie + setInterval:只能同域,并且耗费资源过多,需要不断获取 Cookie 以判断 B 是否传消息给 A 页面。
全部评论

相关推荐

点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务