瀏覽器跨標(biāo)簽頁(yè)通信的8種常見(jiàn)的方式

一:什么是瀏覽器跨標(biāo)簽頁(yè)通信?

瀏覽器跨標(biāo)簽頁(yè)通信是指在同一個(gè)瀏覽器窗口中的多個(gè)標(biāo)簽頁(yè)之間進(jìn)行數(shù)據(jù)交流和信息傳遞的過(guò)程凡简。通常情況下逼友,每個(gè)標(biāo)簽頁(yè)都是一個(gè)獨(dú)立的瀏覽器上下文,它們之間是相互隔離的秤涩,無(wú)法直接訪問(wèn)對(duì)方的數(shù)據(jù)或進(jìn)行通信帜乞。

跨標(biāo)簽頁(yè)通信的目的是允許這些相互隔離的標(biāo)簽頁(yè)之間進(jìn)行信息共享和交互。通過(guò)跨標(biāo)簽頁(yè)通信筐眷,可以實(shí)現(xiàn)數(shù)據(jù)的共享黎烈、狀態(tài)的同步、消息的傳遞等功能匀谣。

例如照棋,在一個(gè)標(biāo)簽頁(yè)中進(jìn)行了某個(gè)操作,希望其他標(biāo)簽頁(yè)能夠及時(shí)獲得相關(guān)的變化和通知武翎,就需要使用跨標(biāo)簽頁(yè)通信機(jī)制來(lái)實(shí)現(xiàn)這種交互烈炭。

二:瀏覽器跨標(biāo)簽頁(yè)通信主要用在哪些需求里面

瀏覽器跨標(biāo)簽頁(yè)通信主要用于以下幾種需求:

1:數(shù)據(jù)共享:當(dāng)多個(gè)標(biāo)簽頁(yè)需要訪問(wèn)和共享相同的數(shù)據(jù)時(shí),跨標(biāo)簽頁(yè)通信可以用于在這些標(biāo)簽頁(yè)之間傳遞數(shù)據(jù)宝恶,確保它們保持同步符隙。

2:狀態(tài)同步:在一些應(yīng)用中,可能會(huì)有多個(gè)標(biāo)簽頁(yè)用于展示相同的應(yīng)用狀態(tài)或會(huì)話(huà)狀態(tài)垫毙。通過(guò)跨標(biāo)簽頁(yè)通信霹疫,可以實(shí)現(xiàn)狀態(tài)的同步,使得在一個(gè)標(biāo)簽頁(yè)中的操作能夠即時(shí)反映到其他標(biāo)簽頁(yè)上综芥。

3:消息通知:跨標(biāo)簽頁(yè)通信可以用于實(shí)現(xiàn)在一個(gè)標(biāo)簽頁(yè)中發(fā)送消息更米,然后其他標(biāo)簽頁(yè)接收并展示這些消息的功能。

4:共享資源:在某些場(chǎng)景下毫痕,可能需要在多個(gè)標(biāo)簽頁(yè)之間共享某些資源征峦,如網(wǎng)絡(luò)連接迟几、音頻/視頻播放器等。

5:多窗口管理:對(duì)于一些具有多個(gè)窗口的應(yīng)用栏笆,跨標(biāo)簽頁(yè)通信可以用于實(shí)現(xiàn)窗口之間的聯(lián)動(dòng)和數(shù)據(jù)同步类腮。

三:瀏覽器跨標(biāo)簽頁(yè)通信可以通過(guò)以下幾種常見(jiàn)方式實(shí)現(xiàn):

1:LocalStorage 或 SessionStorage:使用 Web 存儲(chǔ)機(jī)制(LocalStorage 或 SessionStorage)可以在不同標(biāo)簽頁(yè)之間共享數(shù)據(jù)。一個(gè)標(biāo)簽頁(yè)可以將數(shù)據(jù)存儲(chǔ)在 LocalStorage 或 SessionStorage 中蛉加,其他標(biāo)簽頁(yè)可以監(jiān)聽(tīng)存儲(chǔ)事件來(lái)獲取更新的數(shù)據(jù)蚜枢。

使用 LocalStorage 或 SessionStorage 實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信的一個(gè)簡(jiǎn)單案例代碼:

// 在一個(gè)標(biāo)簽頁(yè)中寫(xiě)入數(shù)據(jù)到 LocalStorage 或 SessionStorage
localStorage.setItem('sharedData', 'Hello from Tab 1');
// 或者 sessionStorage.setItem('sharedData', 'Hello from Tab 1');

// 在其他標(biāo)簽頁(yè)中監(jiān)聽(tīng)存儲(chǔ)事件,并獲取更新的數(shù)據(jù)
window.addEventListener('storage', function(event) {
  if (event.key === 'sharedData') {
    const newData = event.newValue;
    console.log('Received updated data:', newData);
  }
});

// 在另一個(gè)標(biāo)簽頁(yè)中更新數(shù)據(jù)
localStorage.setItem('sharedData', 'Hello from Tab 2');
// 或者 sessionStorage.setItem('sharedData', 'Hello from Tab 2');

在這個(gè)例子中针饥,首先在一個(gè)標(biāo)簽頁(yè)中通過(guò)localStorage.setItem()sessionStorage.setItem()方法將數(shù)據(jù)寫(xiě)入到LocalStorageSessionStorage中厂抽。然后,在其他標(biāo)簽頁(yè)中通過(guò)監(jiān)聽(tīng) storage 事件來(lái)捕獲存儲(chǔ)事件丁眼,并判斷事件的 key 是否為我們共享的數(shù)據(jù) sharedData筷凤,如果是,則獲取更新的數(shù)據(jù) newValue 并進(jìn)行處理苞七。

接下來(lái)藐守,在另一個(gè)標(biāo)簽頁(yè)中通過(guò) localStorage.setItem()sessionStorage.setItem()方法更新數(shù)據(jù)。

2:Broadcast Channel API:Broadcast Channel API 允許不同標(biāo)簽頁(yè)之間通過(guò)共享的通道進(jìn)行消息廣播和接收蹂风。一個(gè)標(biāo)簽頁(yè)可以通過(guò)通道發(fā)送消息卢厂,其他訂閱了相同通道的標(biāo)簽頁(yè)可以接收到這些消息。

使用 Broadcast Channel API 實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信的一個(gè)簡(jiǎn)單案例代碼:

在發(fā)送消息的標(biāo)簽頁(yè)中:

// 創(chuàng)建一個(gè)廣播通道
const channel = new BroadcastChannel('myChannel');

// 發(fā)送消息
channel.postMessage('Hello from Tab 1');

在接收消息的標(biāo)簽頁(yè)中:

// 創(chuàng)建一個(gè)廣播通道
const channel = new BroadcastChannel('myChannel');

// 監(jiān)聽(tīng)消息事件
channel.onmessage = function(event) {
  const message = event.data;
  console.log('Received message:', message);
};

首先在發(fā)送消息的標(biāo)簽頁(yè)中創(chuàng)建一個(gè)Broadcast Channel惠啄,并指定一個(gè)唯一的通道名稱(chēng)(這里使用 'myChannel')曙聂。通過(guò) channel.postMessage()方法發(fā)送消息到該通道渔嚷。

在接收消息的標(biāo)簽頁(yè)中廓译,同樣創(chuàng)建一個(gè)具有相同通道名稱(chēng)的 Broadcast Channel促王。然后薄疚,通過(guò)為 channel.onmessage 賦值一個(gè)函數(shù)蹄咖,來(lái)監(jiān)聽(tīng)消息事件巧婶。當(dāng)接收到消息時(shí)贪染,事件對(duì)象 event 中的 data 屬性將包含發(fā)送的消息內(nèi)容越走,我們可以在監(jiān)聽(tīng)函數(shù)中獲取并處理該消息棚品。

3:SharedWorker:SharedWorker 是一種在多個(gè)標(biāo)簽頁(yè)之間共享的后臺(tái)線程。標(biāo)簽頁(yè)可以通過(guò) SharedWorker 進(jìn)行通信廊敌,發(fā)送消息和接收消息铜跑。這種方式需要使用 JavaScript 的 Worker API。

使用 SharedWorker 實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信的一個(gè)簡(jiǎn)單案例代碼:

在發(fā)送消息的標(biāo)簽頁(yè)中:

// 創(chuàng)建一個(gè) SharedWorker
const worker = new SharedWorker('worker.js');

// 發(fā)送消息
worker.port.postMessage('Hello from Tab 1');

在共享的 Worker 腳本文件 worker.js 中:

// 監(jiān)聽(tīng)連接事件
self.onconnect = function(event) {
  const port = event.ports[0];
  
  // 監(jiān)聽(tīng)消息事件
  port.onmessage = function(event) {
    const message = event.data;
    console.log('Received message:', message);
  };
  
  // 發(fā)送消息
  port.postMessage('Hello from Worker');
};

在發(fā)送消息的標(biāo)簽頁(yè)中創(chuàng)建一個(gè) SharedWorker骡澈,并指定共享的 Worker 腳本文件路徑為 'worker.js'锅纺。然后,通過(guò) worker.port.postMessage()方法發(fā)送消息到 SharedWorker肋殴。

在共享的 Worker 腳本文件 worker.js 中囤锉,通過(guò)監(jiān)聽(tīng) self.onconnect 事件來(lái)捕獲連接事件坦弟,并獲取與標(biāo)簽頁(yè)之間的通信端口 port。然后官地,通過(guò)為 port.onmessage 賦值一個(gè)函數(shù)酿傍,來(lái)監(jiān)聽(tīng)消息事件。當(dāng)接收到消息時(shí)驱入,事件對(duì)象 event 中的 data 屬性將包含發(fā)送的消息內(nèi)容赤炒,我們可以在監(jiān)聽(tīng)函數(shù)中獲取并處理該消息。

4:Service Worker:Service Worker 是一種獨(dú)立于網(wǎng)頁(yè)的腳本亏较,可以在后臺(tái)運(yùn)行莺褒,提供離線緩存和消息傳遞等功能。標(biāo)簽頁(yè)可以通過(guò) Service Worker 進(jìn)行通信雪情,發(fā)送消息和接收消息遵岩。

5:Window.postMessage():Window.postMessage() 方法允許在不同的窗口或標(biāo)簽頁(yè)之間安全地傳遞消息。通過(guò)調(diào)用 postMessage() 方法并指定目標(biāo)窗口的 origin旺罢,可以將消息發(fā)送到其他標(biāo)簽頁(yè)旷余,并通過(guò)監(jiān)聽(tīng) message 事件來(lái)接收消息。

使用 window.postMessage() 實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信的一個(gè)簡(jiǎn)單案例代碼:

在發(fā)送消息的標(biāo)簽頁(yè)中:

// 監(jiān)聽(tīng)消息事件
window.addEventListener('message', function(event) {
  // 確保消息來(lái)自預(yù)期的源
  if (event.origin !== 'http://example.com') {
    return;
  }

  const message = event.data;
  console.log('Received message:', message);
});

// 發(fā)送消息到其他標(biāo)簽頁(yè)
const targetWindow = window.open('http://example.com/otherpage', '_blank');
targetWindow.postMessage('Hello from Tab 1', 'http://example.com');

在接收消息的標(biāo)簽頁(yè)中

// 監(jiān)聽(tīng)消息事件
window.addEventListener('message', function(event) {
  // 確保消息來(lái)自預(yù)期的源
  if (event.origin !== 'http://example.com') {
    return;
  }

  const message = event.data;
  console.log('Received message:', message);

  // 回復(fù)消息
  event.source.postMessage('Hello from Other Tab', event.origin);
});

在發(fā)送消息的標(biāo)簽頁(yè)中通過(guò)使用 window.addEventListener('message', ...) 監(jiān)聽(tīng)消息事件扁达。在事件處理函數(shù)中正卧,可以用 event.origin 來(lái)驗(yàn)證消息的來(lái)源是否符合預(yù)期。然后跪解,可以用 event.data 獲取到發(fā)送的消息內(nèi)容炉旷,并進(jìn)行相應(yīng)的操作。

在發(fā)送消息的標(biāo)簽頁(yè)中叉讥,用 window.open() 打開(kāi)了一個(gè)新的標(biāo)簽頁(yè)(http://example.com/otherpage)窘行,然后通用 targetWindow.postMessage() 向該標(biāo)簽頁(yè)發(fā)送消息。在這里图仓,我們指定了消息的目標(biāo)窗口和預(yù)期的來(lái)源(即目標(biāo)標(biāo)簽頁(yè)的 URL)罐盔。

在接收消息的標(biāo)簽頁(yè)中,同樣通過(guò) window.addEventListener('message', ...) 監(jiān)聽(tīng)消息事件救崔,并在事件處理函數(shù)中進(jìn)行相應(yīng)的操作惶看。

6:使用 Cookies:可以將需要共享的數(shù)據(jù)存儲(chǔ)在 Cookies 中,并在不同的標(biāo)簽頁(yè)之間讀取和更新這些 Cookies六孵。當(dāng)一個(gè)標(biāo)簽頁(yè)更新數(shù)據(jù)時(shí)纬黎,將數(shù)據(jù)寫(xiě)入到 Cookies 中,其他標(biāo)簽頁(yè)可以通過(guò)監(jiān)聽(tīng) Cookies 變化事件或定時(shí)讀取 Cookies 來(lái)獲取最新的數(shù)據(jù)劫窒。

使用 Cookies 進(jìn)行通信是一種簡(jiǎn)單的方法本今,但它主要用于在客戶(hù)端和服務(wù)器之間傳遞數(shù)據(jù),而不是直接實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信。Cookies 會(huì)自動(dòng)在客戶(hù)端和服務(wù)器之間進(jìn)行傳遞冠息,因此可以在不同的標(biāo)簽頁(yè)之間共享數(shù)據(jù)挪凑。

下面是一個(gè)使用 Cookies 在標(biāo)簽頁(yè)之間傳遞數(shù)據(jù)的簡(jiǎn)單案例代碼:

在發(fā)送消息的標(biāo)簽頁(yè)中:

// 設(shè)置 Cookie
document.cookie = 'sharedData=Hello from Tab 1';

在接收消息的標(biāo)簽頁(yè)中:

// 獲取 Cookie 值
const cookies = document.cookie;
const cookieArr = cookies.split(';');

let sharedData = null;
for (let i = 0; i < cookieArr.length; i++) {
  const cookie = cookieArr[i].trim();
  if (cookie.startsWith('sharedData=')) {
    sharedData = cookie.substring('sharedData='.length, cookie.length);
    break;
  }
}

console.log('Received message:', sharedData);

7:使用 IndexedDB:IndexedDB 是瀏覽器提供的一個(gè)客戶(hù)端數(shù)據(jù)庫(kù),可以在不同的標(biāo)簽頁(yè)之間存儲(chǔ)和讀取數(shù)據(jù)逛艰。一個(gè)標(biāo)簽頁(yè)可以將數(shù)據(jù)寫(xiě)入 IndexedDB岖赋,其他標(biāo)簽頁(yè)可以監(jiān)聽(tīng) IndexedDB 的變化事件或定時(shí)從 IndexedDB 中讀取數(shù)據(jù)來(lái)實(shí)現(xiàn)數(shù)據(jù)的共享和狀態(tài)的同步。

下面是一個(gè)使用IndexedDB進(jìn)行通信的簡(jiǎn)單案例代碼:

// 打開(kāi)或創(chuàng)建IndexedDB數(shù)據(jù)庫(kù)
const request = indexedDB.open('myDatabase', 1);

// 成功打開(kāi)數(shù)據(jù)庫(kù)
request.onsuccess = function(event) {
  const db = event.target.result;

  // 創(chuàng)建一個(gè)對(duì)象存儲(chǔ)空間(類(lèi)似表)
  const objectStore = db.createObjectStore('messages', { keyPath: 'id', autoIncrement: true });

  // 添加一條消息到對(duì)象存儲(chǔ)空間
  const message = { text: 'Hello, World!' };
  const addRequest = objectStore.add(message);

  addRequest.onsuccess = function(event) {
    console.log('消息已添加到IndexedDB');
  };

  addRequest.onerror = function(event) {
    console.error('添加消息到IndexedDB時(shí)發(fā)生錯(cuò)誤');
  };

  // 從對(duì)象存儲(chǔ)空間獲取所有消息
  const getAllRequest = objectStore.getAll();

  getAllRequest.onsuccess = function(event) {
    const messages = event.target.result;
    console.log('所有消息:', messages);
  };

  getAllRequest.onerror = function(event) {
    console.error('獲取消息時(shí)發(fā)生錯(cuò)誤');
  };
};

// 打開(kāi)或創(chuàng)建數(shù)據(jù)庫(kù)時(shí)發(fā)生錯(cuò)誤
request.onerror = function(event) {
  console.error('打開(kāi)/創(chuàng)建數(shù)據(jù)庫(kù)時(shí)發(fā)生錯(cuò)誤');
};

// 數(shù)據(jù)庫(kù)版本變更
request.onupgradeneeded = function(event) {
  const db = event.target.result;

  // 創(chuàng)建一個(gè)對(duì)象存儲(chǔ)空間
  const objectStore = db.createObjectStore('messages', { keyPath: 'id', autoIncrement: true });

  console.log('數(shù)據(jù)庫(kù)版本已更新');
};

8:使用服務(wù)器端存儲(chǔ):將需要共享的數(shù)據(jù)存儲(chǔ)在服務(wù)器端瓮孙,標(biāo)簽頁(yè)之間通過(guò)與服務(wù)器進(jìn)行通信來(lái)獲取和更新數(shù)據(jù)唐断。可以使用 AJAX杭抠、WebSocket 或其他網(wǎng)絡(luò)通信技術(shù)來(lái)實(shí)現(xiàn)與服務(wù)器的數(shù)據(jù)交互脸甘。

注意:使用服務(wù)器端存儲(chǔ)的方法可能需要進(jìn)行網(wǎng)絡(luò)請(qǐng)求,可能會(huì)涉及到延遲和帶寬消耗偏灿。

而使用本地存儲(chǔ)(如LocalStorage丹诀、SessionStorage)或客戶(hù)端數(shù)據(jù)庫(kù)(如IndexedDB)的方法更加直接和快速,適用于較小規(guī)模的數(shù)據(jù)共享和狀態(tài)同步翁垂。

這些是常見(jiàn)的瀏覽器跨標(biāo)簽頁(yè)通信的方式铆遭。具體選擇哪種方式取決于你的需求和使用場(chǎng)景。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沿猜,一起剝皮案震驚了整個(gè)濱河市枚荣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌啼肩,老刑警劉巖橄妆,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異祈坠,居然都是意外死亡害碾,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)赦拘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)慌随,“玉大人,你說(shuō)我怎么就攤上這事躺同「蟛拢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵笋籽,是天一觀的道長(zhǎng)蹦漠。 經(jīng)常有香客問(wèn)我椭员,道長(zhǎng)车海,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮侍芝,結(jié)果婚禮上研铆,老公的妹妹穿的比我還像新娘。我一直安慰自己州叠,他們只是感情好棵红,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著咧栗,像睡著了一般逆甜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上致板,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天交煞,我揣著相機(jī)與錄音,去河邊找鬼斟或。 笑死素征,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萝挤。 我是一名探鬼主播御毅,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怜珍!你這毒婦竟也來(lái)了端蛆?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤酥泛,失蹤者是張志新(化名)和其女友劉穎欺税,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體揭璃,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晚凿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瘦馍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歼秽。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖情组,靈堂內(nèi)的尸體忽然破棺而出燥筷,到底是詐尸還是另有隱情,我是刑警寧澤院崇,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布肆氓,位于F島的核電站,受9級(jí)特大地震影響底瓣,放射性物質(zhì)發(fā)生泄漏谢揪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拨扶。 院中可真熱鬧凳鬓,春花似錦、人聲如沸患民。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)匹颤。三九已至仅孩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間印蓖,已是汗流浹背杠氢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留另伍,地道東北人鼻百。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像摆尝,于是被迫代替她去往敵國(guó)和親温艇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容