如何实现网页标签页之间的通信

398 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

在前端web网页开发过程中,经常会遇到新开同域或跨域的第三方页面。新的页面就会涉及必要参数传递、页面间通信的问题。标签页传参和标签页通信是不同的意思,常见的标签页之间的传参方式有URL、Storage(包括localStorage和sessionStorage),Vue项目还可以使用vue-router、Vuex等;如果要实现标签页之间的通信又有哪些方法呢?本文主要介绍三种方式:websocket、localStorage、sharedWorker。

使用WebSocket

websocket是一种可实现客户端和服务端双向通信的协议,不同于HTTP协议。HTTP协议只能由客户端发起通信,服务端不能主动发起。有了websocket,怎么实现标签页之间的通信呢。很简单,tabA实现一个WebSocket,并拥有发送和接收消息的能力,tabB也实现一个WebSocket,也拥有发送和接收消息的能力。两者将消息经由服务器发送给对方,在收到消息后处理。

这种方式可以避免跨域问题,但是缺点是需要服务端做中间处理,如果只是简单的两个标签页之间的通信,使用WebSocket有点"大材小用"。

使用localStorage(推荐)

根据Storage的特性,localStorage只能访问同域的数据。因此这些标签页需要同域才能使用localStorage来通信。首先在tabA监听storage是否变化,然后跳转到tabB后,在tabB页面修改localStorage里面的数据,tabA就能根据监听到的storage变化,过滤出是否有自己想要的值,注意此处不能使用sessionStorage。sessionStorage无法在多个标签页之间共享,哪怕是同源、同页面。

实现代码

// tabA
window.addEventListener('storage', event => {
  console.log('监听storage改变', event, event.key, event.newValue);
});


// tabB
const btn = document.createElement('button');
ducoment.body.appendChild(btn);
btn.addEventListener('click', () => {
  localStorage.setItem('tabBInfo', JSON.stringify({
    text: 'this is tabB',
    time: Date.now(), // 使用当前时间,保证每次发消息都是不同的
  }))
})

注意事项

  • 多个标签页必须同源
  • 此方案主要是监听Storage的变化实现通信,因此只有改变了localStorage的值才能监听到

使用sharedWorker

js是单线程执行,可通过webWorker开启"多线程"。webWorker不能操作dom,但是可以执行某些任务,sharedWorker作为webWorker中的一种,可用于同域页面间的通信。

实现代码

// worker.js
const ports = new Set()
onconnect = event => {
  let port = event.ports[0]
  ports.add(port)
  port.onmessage = e => {
    ports.forEach(p => {
      p.postMessage(e.data)
    })
  }
  port.start()
}
// tabA
const worker = new SharedWorker('./worker.js')
worker.port.onmessage = e => {
  console.log('tabA 收到消息:', e.data)
}
// tabB
const worker = new SharedWorker('./worker.js')
const btn = document.createElement('button');
ducoment.body.appendChild(btn);
btn.addEventListener('click', () => {
  worker.port.postMessage('来自tabB的消息')
})

注意事项

  • SharedWorker可以被多个窗口页面使用,但是这些页面必须是同源的,即同协议、端口、host。
  • SharedWorker通信依赖于端口,因此需要在node环境下执行,而不是直接访问html
  • 发消息采用postMessage,接收消息采用onmessage
  • SharedWorker不支持ie11,兼容性尚可

总结

本文一共列举了三种多标签页间的通信方式,根据场景不同可选择不同的实现方式,优缺点如下:

  • WebSocket 可跨域通信,但是存在服务端成本
  • localStorage不可跨域共享,简单易上手,同域通信更推荐。关键是监听Storage的变化
  • SharedWorker不可跨域通信,存在兼容性,且需要在node环境下才能执行。对比localStorage,SharedWorker监听的是端口间的通信,发送和接收消息更灵活;localStorage则需要保证修改和监听key值保持一致,如果需要的key值很多,不管是修改方还是接收方,代码都会比较冗余。

原创不易,转载请注明出处