js 跨浏览器tab页通信

跨页面通信技术:BroadcastChannel与window.postMessage解析
本文介绍了在商品列表页面中实现新增商品后立即更新列表的跨页面通信问题。主要探讨了三种解决方案:使用BroadcastChannel、window.postMessage以及storageEvent。BroadcastChannel简单易用,能传递任意数据;window.postMessage需要目标窗口引用,支持跨域;storageEvent通过监听localStorage变更实现通信,但仅限字符串。每种方法都有其适用场景和限制。

问题

今天遇到一个问题,在商品列表页面,打开一个新增商品的页面,新增完后,商品列表要立刻显示新增商品,这就需要新增商品后,通知订单列表页,也就是常说的跨tab页通信。跨tab页通信,不仅包含常见的跨tab页,还包括跨window窗口、跨frame、跨iframe。

解决方案

同源下,可使用BroadCastChannel实现跨tab页通信。

  • 发送端
    • 如果重复创建相同名称的channel,j底层channel只会创建一次。
// If it is the first to connect to that broadcast channel name, 
// the underlying channel is created.
// Connection to a broadcast channel
const bc = new BroadcastChannel('test_channel');
// Example of sending of a very simple message
bc.postMessage('This is a test message.');
  • 接收端
// Connection to a broadcast channel
const bc = new BroadcastChannel('test_channel');
// A handler that only logs the event to the console:
bc.onmessage = function (ev) { console.log(ev); }
  • 关闭
// Disconnect the channel
bc.close();

这种方法比较简单,可以传任何数据对象(字符串、对象、数字等等),也是我比较推荐的方式。

window postMessage 方式

除了使用上述方式,还可以使用window.postMessage,缺点就是要持有目标window的引用,当页面刷新后,会失去目标window引用;优点就是可实现跨域通信。

  • 发送端
//发送事件
targetWindow.postMessage(message, targetOrigin)
  • 接收端
//接收事件
window.addEventListener("message", (event) => {
  if (event.origin !== "http://localhost:8080")
    return;
  // Do something
}, false);

storage event方式

也可以使用storage event来实现,原理就是监听storage set事件,来达到同步,但只能发送字符串,另外当前页面也不会获取本页发出的set事件。

  • 发送端
//发送事件
window.localStorage.setItem("loggedIn", "true");
  • 接收端
//接收事件
window.addEventListener('storage', (event) => {
 if (event.storageArea != localStorage) return;
 if (event.key === 'loggedIn') {
   // Do something with event.newValue
 }
});
<think>我们正在讨论的是JavaScript中实现跨浏览器标签通信,特别是使用storage事件的方法。 根据引用[1]和引用[2],我们可以使用localStorage或sessionStorage来存储共享数据,并通过监听storage事件来步不标签的数据变化。 步骤: 1. 在一个标签中设置或修改localStorage或sessionStorage的数据。 2. 在其他标签中,通过监听window对象的storage事件来捕获数据变化,并执行相应的操作。 注意点: - storage事件只在一个名下的不标签之间触发,且不会在设置数据的当前标签触发(即,只有其他面会触发)。 - 为了避免不必要的步循环,我们可以在设置数据时添加一个标记,或者通过事件中的key来判断我们关心的数据变化。 下面是一个简单的示例代码: 在标签A中,我们设置数据: ```javascript // 设置数据到localStorage localStorage.setItem('sharedData', JSON.stringify({ message: 'Hello from Tab A' })); ``` 在标签B(以及其他标签)中,我们监听storage事件: ```javascript window.addEventListener('storage', function(event) { // 当localStorage的某个键发生变化时触发 if (event.key === 'sharedData') { // 解析新值 const data = JSON.parse(event.newValue); console.log('Received data:', data); // 在这里可以更新面内容或执行其他操作 } }); ``` 但是,需要注意的是,当一个标签修改了localStorage,它自己不会触发storage事件。只有其他源的标签才会触发。 另外,引用[2]中提到,在组件销毁前需要移除事件监听,以避免内存泄漏(在单应用中尤为重要)。 优化:为了避免多个标签时修改数据导致循环,我们可以设计一个状态管理机制,例如只允许特定角色(如主标签)来更新数据,或者使用版本号来控制更新。 相关问题: 1. 使用storage事件进行标签通信有什么限制? 2. 除了localStorage和sessionStorage,还有哪些方法可以实现标签通信? 3. 如何确保标签通信的安全性和数据一致性?</think>在 JavaScript 中实现跨浏览器标签通信,使用 `localStorage` 或 `sessionStorage` 结合 `storage` 事件是最常用的方法之一。这种技术允许源的不标签之间共享数据和状态更新。 ### 实现步骤 1. **数据写入** 在任意标签中修改存储数据: ```javascript // 设置共享数据 localStorage.setItem('sharedData', JSON.stringify({ message: '标签更新通知', timestamp: Date.now() })); ``` 2. **事件监听** 在其他标签监听存储变化: ```javascript window.addEventListener('storage', (event) => { // 过滤非目标数据的变化 if (event.key === 'sharedData') { const data = JSON.parse(event.newValue); console.log('收到更新:', data); // 执行步操作(如更新UI/跳转面) if (data.path) window.location.href = data.path; } }); ``` 3. **清理机制** 在面卸载时移除监听(单应用需注意): ```javascript window.addEventListener('beforeunload', () => { window.removeEventListener('storage', handlerFunction); }); ``` ### 关键特性 | 特性 | 说明 | |--------------------|----------------------------------------------------------------------| | **源策略** | 仅限相协议+名+端口的面间通信[^1] | | **事件触发范围** | 仅在**其他标签**触发,当前修改不触发[^2] | | **数据格式** | 需手动序列化/反序列化(`JSON.stringify`/`JSON.parse`) | | **容量限制** | 通常为 5MB(不浏览器有差异) | | **通信延迟** | 瞬时触发(通常在 10ms 内) | ### 示例场景 ```javascript // 标签A:用户操作时步导航 document.getElementById('nav-link').addEventListener('click', () => { localStorage.setItem('syncNavigation', JSON.stringify({ path: '/new-page', triggeredBy: 'Tab-A' })); }); // 标签B:自动跟随导航 window.addEventListener('storage', (e) => { if (e.key === 'syncNavigation') { const { path } = JSON.parse(e.newValue); window.location.href = path; // 自动跳转相面 } }); ``` ### 注意事项 1. **隐私模式限制**:部分浏览器的隐私模式下 `localStorage` 不可用 2. **频率控制**:高频更新可能导致性能问题(需节流处理) 3. **数据类型**:只能存储字符串,复杂对象需序列化 4. **浏览器兼容**:IE8+ 支持,但 IE 某些版本有事件触发延迟 替代方案包括 `BroadcastChannel API`、`SharedWorker` 和 `window.postMessage`,但 `storage` 事件方案具有最佳浏览器兼容性(支持到 IE8)[^1][^2]。 [^1]: 通过监听 `storage` 事件实现标签数据步 [^2]: 组件销毁前需移除事件监听避免内存泄漏
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值