JavaScript常見(jiàn)的跨標(biāo)簽頁(yè)通信方式總結(jié)
引言
跨標(biāo)簽頁(yè)通信是指在瀏覽器中的不同標(biāo)簽頁(yè)之間進(jìn)行數(shù)據(jù)傳遞和通信的過(guò)程。在傳統(tǒng)的Web開(kāi)發(fā)中,每個(gè)標(biāo)簽頁(yè)都是相互獨(dú)立的,無(wú)法直接共享數(shù)據(jù)。然而,有時(shí)候我們需要在不同的標(biāo)簽頁(yè)之間進(jìn)行數(shù)據(jù)共享或者實(shí)現(xiàn)一些協(xié)同操作,這就需要使用跨標(biāo)簽頁(yè)通信來(lái)實(shí)現(xiàn)。
常見(jiàn)的跨標(biāo)簽頁(yè)方案如下
- BroadCast Channel
- Service Worker
- LocalStorage window.onstorage 監(jiān)聽(tīng)
- window.open、window.postMessage
- Shared Worker 定時(shí)器輪詢( setInterval )
- IndexedDB 定時(shí)器輪詢( setInterval )
- cookie 定時(shí)器輪詢( setInterval )
- Websocket
本文先介紹前面4種
BroadCast Channel
Broadcast Channel API 可以實(shí)現(xiàn)同源下瀏覽器不同窗口,Tab 頁(yè),frame 或者 iframe 下的(通常是同一個(gè)網(wǎng)站下不同的頁(yè)面) 之間的簡(jiǎn)單通訊。
通過(guò)創(chuàng)建一個(gè)監(jiān)聽(tīng)某個(gè)頻道下的 BroadcastChannel
對(duì)象,你可以接收發(fā)送給該頻道的所有消息。一個(gè)有意思的點(diǎn)是,你不需要再維護(hù)需要通信的 iframe 或 worker 的索引。它們可以通過(guò)構(gòu)造 BroadcastChannel
來(lái)簡(jiǎn)單地“訂閱”特定頻道,并在它們之間進(jìn)行全雙工(雙向)通信。
示例
通過(guò)創(chuàng)建一個(gè)廣播頻道,并在不同的標(biāo)簽頁(yè)中監(jiān)聽(tīng)該頻道,可以實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信。
例如,在一個(gè)標(biāo)簽頁(yè)中發(fā)送消息:
const channel = new BroadcastChannel('myChannel'); channel.postMessage('Hello from Tab 1!');
在另一個(gè)標(biāo)簽頁(yè)中接收消息:
const channel = new BroadcastChannel('myChannel'); channel.onmessage = function(event) { console.log(event.data); // 輸出:Hello from Tab 1! };
可以通過(guò)調(diào)用 BroadcastChannel
對(duì)象的 close()
方法,可以離開(kāi)頻道。這將斷開(kāi)該對(duì)象和其關(guān)聯(lián)的頻道之間的聯(lián)系,并允許它被垃圾回收。
// 斷開(kāi)頻道連接 channel.close();
Service Worker
Service worker 本質(zhì)上充當(dāng) Web 應(yīng)用程序、瀏覽器與網(wǎng)絡(luò)(可用時(shí))之間的代理服務(wù)器。這個(gè) API 旨在創(chuàng)建有效的離線體驗(yàn),它會(huì)攔截網(wǎng)絡(luò)請(qǐng)求并根據(jù)網(wǎng)絡(luò)是否可用來(lái)采取適當(dāng)?shù)膭?dòng)作、更新來(lái)自服務(wù)器的的資源。它還提供入口以推送通知和訪問(wèn)后臺(tái)同步 API。
Service worker 是一個(gè)注冊(cè)在指定源和路徑下的事件驅(qū)動(dòng)worker。它采用 JavaScript 文件的形式,控制關(guān)聯(lián)的頁(yè)面或者網(wǎng)站,攔截并修改訪問(wèn)和資源請(qǐng)求,細(xì)粒度地緩存資源。你可以完全控制應(yīng)用在特定情形(最常見(jiàn)的情形是網(wǎng)絡(luò)不可用)下的表現(xiàn)。
使用 ServiceWorkerContainer.register()
方法首次注冊(cè) service worker。如果注冊(cè)成功,service worker 就會(huì)被下載到客戶端并嘗試安裝或激活,這將作用于整個(gè)域內(nèi)用戶可訪問(wèn)的 URL,或者其特定子集。
示例
index.html
<body> <h1>頁(yè)面一</h1> <button>發(fā)送</button> <script> navigator.serviceWorker.register('./sw.js') .then(() => { console.log("service worker 注冊(cè)成功"); }); document.querySelector("button").onclick = function () { navigator.serviceWorker.controller.postMessage('hello'); } </script> </body>
index2.html
<body> <h1>頁(yè)面二</h1> <script> navigator.serviceWorker.register('./sw.js') .then(() => { console.log("service worker 注冊(cè)成功"); }); navigator.serviceWorker.onmessage = function ({ data }) { console.log(data); } </script> </body>
sw.js
self.addEventListener("message",async event=>{ const clients = await self.clients.matchAll(); clients.forEach(function(client){ client.postMessage(event.data) }); });
LocalStorage window.onstorage
存儲(chǔ)在 localStorage
的數(shù)據(jù)可以長(zhǎng)期保留;而當(dāng)頁(yè)面會(huì)話結(jié)束——也就是說(shuō),當(dāng)頁(yè)面被關(guān)閉時(shí),存儲(chǔ)在 sessionStorage
的數(shù)據(jù)會(huì)被清除。
另外,localStorage
中的鍵值對(duì)總是以字符串的形式存儲(chǔ)。 (需要注意,和 js 對(duì)象相比,鍵值對(duì)總是以字符串的形式存儲(chǔ)意味著數(shù)值類型會(huì)自動(dòng)轉(zhuǎn)化為字符串類型).
當(dāng)存儲(chǔ)區(qū)域(localStorage 或 sessionStorage)被修改時(shí),將觸發(fā) storage 事件。
由事件監(jiān)聽(tīng)器發(fā)送給回調(diào)函數(shù)的事件對(duì)象有幾個(gè)屬性如下:
Property | Type | Description |
---|---|---|
target 只讀 | [EventTarget] | 事件目標(biāo) (DOM 樹(shù)中的最大目標(biāo)) |
type 只讀 | [DOMString] | 事件的類型 |
bubbles 只讀 | [Boolean] | 事件通常是否會(huì)出現(xiàn)冒泡 |
cancelable 只讀 | [Boolean] | 事件是否可取消 |
key 只讀 | [DOMString] (string) | 鍵更改時(shí) |
oldValue 只讀 | [DOMString] (string) | 正在更改鍵的舊值 |
newValue 只讀 | [DOMString] (string) | 正在更改鍵的新值 |
url 只讀 | DOMString | 鍵更改的文檔的地址 |
storageArea 只讀 | [Storage] | 受影響的存儲(chǔ)對(duì)象 |
示例
例如,在一個(gè)標(biāo)簽頁(yè)中修改LocalStorage的值:
localStorage.setItem('message', 'Hello from Tab 1!');
在另一個(gè)標(biāo)簽頁(yè)中監(jiān)聽(tīng)LocalStorage的變化:
window.onstorage = function(event) { if (event.key === 'message') { console.log(event.newValue); // 輸出:Hello from Tab 1! } };
window.open、window.postMessage
通過(guò)在一個(gè)標(biāo)簽頁(yè)中使用window.open打開(kāi)另一個(gè)標(biāo)簽頁(yè),并使用window.postMessage進(jìn)行消息傳遞,可以實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信。
window.open()
open() open(url) open(url, target) open(url, target, windowFeatures)
url
: 一個(gè)字符串,表示要加載的資源的 URL 或路徑。如果指定空字符串(""
)或省略此參數(shù),則會(huì)在目標(biāo)瀏覽上下文中打開(kāi)一個(gè)空白頁(yè)。target
: 一個(gè)不含空格的字符串,用于指定加載資源的瀏覽上下文的名稱。windowFeatures
: 一個(gè)字符串,包含以逗號(hào)分隔的窗口特性列表。
window.postMessage() 方法可以安全地實(shí)現(xiàn)跨源通信。通常,對(duì)于兩個(gè)不同頁(yè)面的腳本,只有當(dāng)執(zhí)行它們的頁(yè)面位于具有相同的協(xié)議(通常為 https),端口號(hào)(443 為 https 的默認(rèn)值),以及主機(jī) (兩個(gè)頁(yè)面的模數(shù) Document.domain
設(shè)置為相同的值) 時(shí),這兩個(gè)腳本才能相互通信。window.postMessage() 方法提供了一種受控機(jī)制來(lái)規(guī)避此限制,只要正確的使用,這種方法就很安全。
示例
例如,在一個(gè)標(biāo)簽頁(yè)中發(fā)送消息:
const newTab = window.open('other.html'); newTab.postMessage('Hello from Tab 1!', '*');
在另一個(gè)標(biāo)簽頁(yè)中接收消息:
window.addEventListener('message', function(event) { console.log(event.data); // 輸出:Hello from Tab 1! });
總結(jié)
- BroadCast Channel:使用Broadcast Channel API可以在不同的瀏覽器上下文之間進(jìn)行消息廣播和接收。通過(guò)創(chuàng)建一個(gè)廣播頻道,并在不同的標(biāo)簽頁(yè)中監(jiān)聽(tīng)該頻道,可以實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信。
- Service Worker:Service Worker是一種在瀏覽器后臺(tái)運(yùn)行的腳本,可以攔截和處理網(wǎng)絡(luò)請(qǐng)求。通過(guò)在Service Worker中監(jiān)聽(tīng)和處理消息事件,可以實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信。
- LocalStorage window.onstorage 監(jiān)聽(tīng):通過(guò)在不同的標(biāo)簽頁(yè)中監(jiān)聽(tīng)LocalStorage的變化,可以實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信。當(dāng)一個(gè)標(biāo)簽頁(yè)修改LocalStorage的值時(shí),其他標(biāo)簽頁(yè)可以通過(guò)監(jiān)聽(tīng)storage事件來(lái)獲取最新值。
- window.open、window.postMessage:通過(guò)在一個(gè)標(biāo)簽頁(yè)中使用window.open打開(kāi)另一個(gè)標(biāo)簽頁(yè),并使用window.postMessage進(jìn)行消息傳遞,可以實(shí)現(xiàn)跨標(biāo)簽頁(yè)通信。這種方式適用于需要直接傳遞數(shù)據(jù)或消息的場(chǎng)景。
這些方案各有特點(diǎn)和適用場(chǎng)景。Broadcast Channel
適用于需要實(shí)時(shí)廣播消息給所有打開(kāi)的標(biāo)簽頁(yè)的場(chǎng)景;Service Worker
適用于需要在后臺(tái)進(jìn)行數(shù)據(jù)處理或者發(fā)送消息給其他標(biāo)簽頁(yè)的場(chǎng)景;LocalStorage window.onstorage監(jiān)聽(tīng)
適用于需要共享數(shù)據(jù)并及時(shí)獲取更新的場(chǎng)景;window.open、window.postMessage
適用于需要直接傳遞數(shù)據(jù)或消息的場(chǎng)景。
到此這篇關(guān)于JavaScript常見(jiàn)的跨標(biāo)簽頁(yè)通信方式總結(jié)的文章就介紹到這了,更多相關(guān)JavaScript跨標(biāo)簽頁(yè)通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript實(shí)現(xiàn)登錄框拖拽效果
這篇文章主要為大家詳細(xì)介紹了Javascript實(shí)現(xiàn)登錄框拖拽效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10JavaScript生成隨機(jī)數(shù)的各種方法大全
JavaScript 是一門強(qiáng)大的編程語(yǔ)言,在前端和后端開(kāi)發(fā)中廣泛使用,生成隨機(jī)數(shù)是 JavaScript 開(kāi)發(fā)中的常見(jiàn)需求,應(yīng)用場(chǎng)景包括游戲開(kāi)發(fā)、驗(yàn)證碼生成、數(shù)據(jù)模擬等,本文將詳細(xì)介紹 JavaScript 中生成隨機(jī)數(shù)的各種方法,并分析其適用場(chǎng)景和優(yōu)缺點(diǎn),需要的朋友可以參考下2025-03-03JavaScript如何實(shí)現(xiàn)防止重復(fù)的網(wǎng)絡(luò)請(qǐng)求的示例
這篇文章主要介紹了JavaScript如何實(shí)現(xiàn)防止重復(fù)的網(wǎng)絡(luò)請(qǐng)求的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01JavaScript本地存儲(chǔ)的幾種方式小結(jié)
在 JavaScript 中,本地存儲(chǔ)指的是將數(shù)據(jù)保存在用戶的瀏覽器中,能夠在頁(yè)面刷新或關(guān)閉后仍然保留,本文給大家介紹了本地存儲(chǔ)的幾種方式,每種存儲(chǔ)方式的特點(diǎn)、區(qū)別及應(yīng)用場(chǎng)景,需要的朋友可以參考下2024-12-12js中的異步獲取到的數(shù)據(jù)到底能不能賦值給一個(gè)全局變量問(wèn)題
這篇文章主要介紹了js中的異步獲取到的數(shù)據(jù)到底能不能賦值給一個(gè)全局變量問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04小程序?qū)崿F(xiàn)tab標(biāo)簽頁(yè)
這篇文章主要為大家詳細(xì)介紹了小程序?qū)崿F(xiàn)tab標(biāo)簽頁(yè),可點(diǎn)擊切換,滑動(dòng)切換頁(yè)面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11一個(gè)非常好用的文字滾動(dòng)的案例,鼠標(biāo)懸浮可暫停[兩種方案任選]
本文主要介紹了非常好用的文字滾動(dòng)的案例,鼠標(biāo)懸浮可暫停的兩種實(shí)現(xiàn)方案,代碼簡(jiǎn)潔,可收藏備用。需要的朋友來(lái)看下吧2016-12-12