博客 / 詳情

返回

如何跨標籤頁通信

🧑‍💻 寫在開頭

點贊 + 收藏 === 學會🤣🤣🤣

開篇小劇場:為什麼標籤頁要"聊天"?

想象你在網上商城:

標籤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(共享黑板)

🎨 方案1:BroadCast Channel - 對講機頻道

// 所有標籤頁加入同一個"頻道"
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啦

記住:沒有最好的方案,只有最合適的方案!就像選擇工具一樣,用對場景最重要~

如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.