如何跨标签页通信 _

52 阅读3分钟

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

开篇小剧场:为什么标签页要"聊天"?

想象你在网上商城:

标签1:浏览商品页
标签2:开着购物车

当你在标签1点击"加入购物车",标签2的购物车数字应该立即+1!这就是标签页通信的魔力啦!✨

````🎨 方案1:BroadCast Channel(对讲机频道)`

🛠️ 方案2:Service Worker(隐形邮差)

📦 方案3:LocalStorage(共享小本本)

👨‍💻 方案4:Shared Worker(共享办公室)

🕵️‍♂️ 方案5-6:轮询侦查队(IndexedDB``/Cookie``)

👨‍👦 方案7:window.``open``(父子悄悄话)

🌐 方案8:WebSocket(专业电话线)

🧩 方案9:SharedArrayBuffer(共享黑板)

````//` `所有标签页加入同一个``"频道"`

`const channel = new BroadcastChannel(``'shop_channel'``);`

 

`//` `标签1发送消息`

`channel.postMessage({ action: ``'addToCart'``, item: ``'可爱猫猫'` `});`

 

`//` `标签2接收消息`

`channel.onmessage = (event) => {`

`  ``console.log(``'收到消息:'``, event.data);`

`  ``//` `显示:``"收到消息: {action: "``addToCart``", item: "``可爱猫猫``"}"`

`};`

📌 特点:

就像一群人在同一个对讲机频道聊天
现代浏览器都支持(IE除外😅)
适合频繁通信

🛠️ 方案2:Service Worker - 隐形邮差

`//` `service-worker.js`

`self.addEventListener(``'message'``, (event) => {`

`  ``//` `告诉所有标签页`

`  ``self.clients.matchAll().``then``(clients => {`

`    ``clients.forEach(client => client.postMessage(event.data));`

`  ``});`

`});`

 

`//` `标签页代码`

`navigator.serviceWorker.onmessage = (event) => {`

`  ``console.log(``'邮差送来消息:'``, event.data);`

`};`

 

`//` `发送消息`

`navigator.serviceWorker.controller.postMessage(``'快递到啦!'``);`

🎯 适用场景:

PWA应用(比如离线可用的网页)
需要后台同步的场景


📦 方案3:LocalStorage - 共享小本本

`//` `标签1写下留言`

`localStorage.setItem(``'message'``, ``'今晚吃火锅!'``);`

 

`//` `标签2监听小本本变化`

`window.addEventListener(``'storage'``, (event) => {`

`  ``if` `(event.key === ``'message'``) {`

`    ``console.log(``'新留言:'``, event.newValue);`

`  ``}`

`});`

⚠️ 注意:

当前标签页修改不会触发自己的监听
容量约5MB(能写很多小纸条啦)


👨‍💻 方案4:Shared Worker - 共享办公室

`//` `shared-worker.js`

`const ports = []; ``//` `连接的所有标签页`

 

`onconnect = (e) => {`

`  ``const port = e.ports[0];`

`  ``ports.push(port);`

`  ` 

`  ``port.onmessage = (event) => {`

`    ``//` `广播给其他同事`

`    ``ports.forEach(p => p !== port && p.postMessage(event.data));`

`  ``};`

`};`

 

`//` `标签页代码`

`const worker = new SharedWorker(``'shared-worker.js'``);`

`worker.port.onmessage = (event) => {`

`  ``console.log(``'办公室通知:'``, event.data);`

`};`

`worker.port.postMessage(``'大家好呀!'``);`

💡 比喻:

就像多个标签页在一个共享办公室工作
通过中间的worker传递消息


🕵️‍♂️ 方案5-6:轮询侦查队(IndexedDB/Cookie)

`//` `方案5:IndexedDB轮询`

`setInterval(() => {`

`  ``db.get(``'message'``).``then``(val => {`

`    ``if` `(val !== lastMessage) {`

`      ``console.log(``'发现新消息:'``, val);`

`      ``lastMessage = val;`

`    ``}`

`  ``});`

`}, 1000);`

 

`//` `方案6:Cookie轮询`

`setInterval(() => {`

`  ``const msg = getCookie(``'message'``);`

`  ``if` `(msg !== lastMsg) {`

`    ``console.log(``'Cookie消息:'``, msg);`

`    ``lastMsg = msg;`

`  ``}`

`}, 1000);`

🚨 注意:

像不断检查信箱的侦查员
不推荐高频使用(耗电耗资源)


👨‍👦 方案7:window.open - 父子窗口说悄悄话

`//` `父窗口`

`const child = window.``open``(``'child.html'``);`

`child.postMessage(``'乖儿子'``, ``'https://same-origin.com'``);`

 

`//` `子窗口`

`window.opener.postMessage(``'老爸好!'``, ``'https://same-origin.com'``);`

 

`//` `两边都要监听`

`window.addEventListener(``'message'``, (event) => {`

`  ``if` `(event.origin !== ``'https://same-origin.com'``) ``return``;`

`  ``console.log(``'收到:'``, event.data);`

🔒 安全第一:

必须验证event.origin!
就像只接收认识的人的信件


🌐 方案8:WebSocket - 专业电话线

`//` `所有标签页连接同一个WebSocket`

`const socket = new WebSocket(``'wss://example.com/chat'``);`

 

`socket.onmessage = (event) => {`

`  ``console.log(``'服务器通知:'``, event.data);`

`};`

 

`//` `发送消息`

`socket.send(``'标签1发来的消息'``);`

🏆 优势:

实时性最强
适合需要服务器参与的复杂场景


🧩 方案9:SharedArrayBuffer - 共享黑板(高级)

`//` `主线程`

`const buffer = new SharedArrayBuffer(1024);`

`const arr = new Int32Array(buffer);`

 

`//` `可以传递给Worker`

`worker.postMessage({ buffer });`

 

`//` `Worker中修改`

`Atomics.store(arr, 0, 123); ``//` `线程安全写入`

🚧 注意:

需要设置安全响应头
适合高性能计算


🎓 选择指南

实际项目选择建议

1 先试试BroadcastChannel(最简单)
2 需要离线功能?上Service Worker
3 大量数据共享?SharedWorker等着你
4 要兼容IE?只能用localStorage啦

记住:没有最好的方案,只有最合适的方案!就像选择工具一样,用对场景最重要~

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。