🧑💻 写在开头
点赞 + 收藏 === 学会🤣🤣🤣
开篇小剧场:为什么标签页要"聊天"?
想象你在网上商城:
标签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啦
记住:没有最好的方案,只有最合适的方案!就像选择工具一样,用对场景最重要~