Vue3實(shí)現(xiàn)跨標(biāo)簽頁通信的四種方式
我們假設(shè)我們需求是需要新開一個(gè)頁面,并且這兩個(gè)頁面需要通信,就可以使用到以下的通信方式
1. localStorage+storage事件
原理 :利用瀏覽器同源標(biāo)簽頁共享的
localStorage存儲(chǔ)數(shù)據(jù),并通過storage事件監(jiān)聽數(shù)據(jù)變化。
<!-- src/views/Home.vue -->
<template>
<div>
<h1>Home Page</h1>
</div>
</template>
<script setup>
import { onMounted } from "vue";
onMounted(() => {
// 標(biāo)簽頁 Home:寫入數(shù)據(jù)
localStorage.setItem("message", "Home Page");
});
</script>
localStorage 是 HTML5 新增的一個(gè)會(huì)話存儲(chǔ)對象,它允許網(wǎng)頁在瀏覽器中存儲(chǔ)鍵值對形式的數(shù)據(jù),并且這些數(shù)據(jù)不會(huì)隨著頁面的關(guān)閉而消失,除非手動(dòng)刪除。
<!-- src/views/About.vue -->
<template>
<div>
<h1>About Page</h1>
</div>
</template>
<script setup>
import { onMounted } from "vue";
onMounted(() => {
// 標(biāo)簽頁 About:監(jiān)聽變化
window.addEventListener("storage", (event) => {
if (event.key === "message") {
console.log("收到消息:", event.newValue);
}
});
});
</script>
這樣當(dāng)頁面 Home 設(shè)置 localStorage 的時(shí)候就會(huì)被監(jiān)聽到,達(dá)到一個(gè)不同標(biāo)簽的通信效果。
優(yōu)缺點(diǎn)
? 簡單易用,無需服務(wù)器
? 無法監(jiān)聽當(dāng)前標(biāo)簽頁修改,數(shù)據(jù)需序列化傳輸
?? 注意:sessionStorage無法觸發(fā)跨標(biāo)簽事件,因其數(shù)據(jù)僅窗口級別共享。那么有人就會(huì)有問題了,既然
localStorage可以,那sessionStorage可不可以呢?答案是不行的。因?yàn)?
storage事件的觸發(fā)條件是:當(dāng)localStorage或sessionStorage中的數(shù)據(jù)發(fā)生變化時(shí),除了觸發(fā)變化的窗口(或標(biāo)簽頁)之外,同一源下的其他窗口(或標(biāo)簽頁)會(huì)收到storage事件。由于
sessionStorage的數(shù)據(jù)是窗口(或標(biāo)簽頁)級別的,不同標(biāo)簽頁之間的sessionStorage是相互隔離的,一個(gè)標(biāo)簽頁對sessionStorage的修改不會(huì)影響其他標(biāo)簽頁,因此sessionStorage的變化不會(huì)觸發(fā)其他標(biāo)簽頁的storage事件。
2. BroadcastChannel API
原理 :
BroadcastChannelAPI 是 HTML5 新增的一種在瀏覽器中實(shí)現(xiàn)跨窗口、跨標(biāo)簽頁甚至跨工作線程進(jìn)行通信的機(jī)制。它提供了一種簡單而有效的方式,讓同源的不同瀏覽上下文(如不同窗口、標(biāo)簽頁、iframe或 Web Worker)之間可以相互發(fā)送和接收消息。
<!-- src/views/Home.vue -->
<template>
<div>
<h1>Home Page</h1>
<el-button @click="sendMessage">發(fā)送消息</el-button>
</div>
</template>
<script setup>
const sendMessage = () => {
// 標(biāo)簽頁 Home:發(fā)送消息
// 1. 創(chuàng)建 BroadcastChannel 實(shí)例
// 要使用 BroadcastChannel,首先需要?jiǎng)?chuàng)建一個(gè) BroadcastChannel 實(shí)例,并指定一個(gè)頻道名稱。頻道名稱是一個(gè)字符串,用于標(biāo)識不同的通信頻道。這里的頻道就是 "chat"。
const channel = new BroadcastChannel("chat");
// 2. 發(fā)送消息
// 使用 postMessage 方法向指定頻道發(fā)送消息。消息可以是任何可以序列化的數(shù)據(jù)類型,如字符串、對象、數(shù)組等。
channel.postMessage("Home Message");
};
</script>
<!-- src/views/About.vue -->
<template>
<div>
<h1>About Page</h1>
</div>
</template>
<script setup>
import { onMounted } from "vue";
onMounted(() => {
const channel = new BroadcastChannel("chat");
// 3. 接收消息
// 通過監(jiān)聽 message 事件來接收其他上下文發(fā)送到該頻道的消息。
channel.onmessage = (event) => {
console.log("收到消息:", event.data); // 監(jiān)聽消息
};
});
</script>
這是現(xiàn)代項(xiàng)目中常用的一種通信方式,利用 BroadcastChannel Api 在兩個(gè)頁面分別發(fā)送與監(jiān)聽
優(yōu)缺點(diǎn)
? 實(shí)時(shí)性強(qiáng),代碼簡潔
? 不支持 IE 瀏覽器
?? 需注意頻道名稱全局唯一,避免沖突。
3. WebSocket
原理 :通過服務(wù)器中轉(zhuǎn)消息,實(shí)現(xiàn)全雙工通信。
<template>
<div>
<h1>WebSocket 示例</h1>
<el-button @click="connectWebSocket">連接 WebSocket</el-button>
<el-button @click="sendMessage" :disabled="!socket">發(fā)送消息</el-button>
<el-button @click="closeWebSocket" :disabled="!socket">關(guān)閉連接</el-button>
<ul>
<li v-for="(message, index) in receivedMessages" :key="index">
{{ message }}
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from "vue";
// 存儲(chǔ) WebSocket 實(shí)例
const socket = ref(null);
// 存儲(chǔ)接收到的消息
const receivedMessages = ref([]);
// 連接 WebSocket
const connectWebSocket = () => {
// 創(chuàng)建 WebSocket 實(shí)例,這里以 echo.websocket.org 為例,它是一個(gè)公共的 WebSocket 測試服務(wù)器,省去了自己搭建服務(wù)器的麻煩
socket.value = new WebSocket("wss://echo.websocket.org");
// WebSocket 連接成功時(shí)觸發(fā)
socket.value.onopen = () => {
console.log("WebSocket 連接成功");
receivedMessages.value.push("WebSocket 連接成功");
};
// 接收到服務(wù)器消息時(shí)觸發(fā)
socket.value.onmessage = (event) => {
console.log("接收到消息:", event.data);
receivedMessages.value.push(event.data);
};
// WebSocket 連接關(guān)閉時(shí)觸發(fā)
socket.value.onclose = () => {
console.log("WebSocket 連接已關(guān)閉");
receivedMessages.value.push("WebSocket 連接已關(guān)閉");
socket.value = null;
};
// WebSocket 發(fā)生錯(cuò)誤時(shí)觸發(fā)
socket.value.onerror = (error) => {
console.error("WebSocket 發(fā)生錯(cuò)誤:", error);
receivedMessages.value.push("WebSocket 發(fā)生錯(cuò)誤");
};
};
// 發(fā)送消息到服務(wù)器
const sendMessage = () => {
if (socket.value) {
const message = "Hello, WebSocket!";
socket.value.send(message);
receivedMessages.value.push(`發(fā)送消息: ${message}`);
}
};
// 關(guān)閉 WebSocket 連接
const closeWebSocket = () => {
if (socket.value) {
socket.value.close();
}
};
</script>
實(shí)際項(xiàng)目中 WebSocket 的服務(wù)器一般由后端搭建,這里用一個(gè)公共的測試服務(wù)器為例
優(yōu)缺點(diǎn)
? 支持跨域,實(shí)時(shí)性高
? 需維護(hù)服務(wù)器,復(fù)雜度高
?? 實(shí)際項(xiàng)目需自建服務(wù)器,確保安全性。
4. SharedWorker
原理 :SharedWorke r是一種特殊類型的Worker,它可以在多個(gè)瀏覽器上下文(如窗口、iframe等)之間共享。
<template>
<el-card>
<template #header>
<div class="card-header">SharedWorker 通信示例</div>
</template>
<el-button id="sendMessageButton" @click="sendMessage"
>發(fā)送消息到 SharedWorker</el-button
>
<el-card v-if="response" style="margin-top: 20px">
<template #header>
<div>響應(yīng)內(nèi)容</div>
</template>
<div>{{ response }}</div>
</el-card>
</el-card>
</template>
<script setup>
import { ref, onMounted } from "vue";
// 創(chuàng)建 SharedWorker 實(shí)例,指定工作線程腳本文件路徑
const worker = new SharedWorker("sharedWorker.js");
// 存儲(chǔ)接收到的響應(yīng)
const response = ref("");
const sendMessage = () => {
const message = "Hello, SharedWorker!";
// 向 SharedWorker 發(fā)送消息
worker.port.postMessage(message);
console.log("向 SharedWorker 發(fā)送消息:", message);
};
onMounted(() => {
// 監(jiān)聽 SharedWorker 的消息事件
worker.port.onmessage = function (event) {
const newResponse = event.data;
console.log("從 SharedWorker 接收到響應(yīng):", newResponse);
// 更新響應(yīng)內(nèi)容
response.value = newResponse;
};
// 啟動(dòng)端口通信
worker.port.start();
});
</script>
// sharedWorker.js 文件,需要放在 public
// 創(chuàng)建一個(gè)消息通道,用于在不同上下文和工作線程之間通信
self.onconnect = function (e) {
// 獲取端口對象,用于接收和發(fā)送消息
const port = e.ports[0];
// 監(jiān)聽端口的消息事件
port.onmessage = function (event) {
const message = event.data;
console.log("SharedWorker 接收到消息:", message);
// 向發(fā)送消息的端口回復(fù)消息
const response = `SharedWorker 已收到消息: ${message}`;
port.postMessage(response);
};
};
注意:
同源策略:
SharedWorker遵循同源策略,即sharedWorker.js文件必須與主頁面文件同源(相同的協(xié)議、域名和端口)。如果直接通過file://協(xié)議打開 HTML 文件,會(huì)因同源策略限制而導(dǎo)致SharedWorker無法正常工作。如果想在本地用html文件進(jìn)行測試,需要啟動(dòng)一個(gè)服務(wù)器,Live Serve 可以滿足需求。文件路徑:在 Vue 項(xiàng)目中,通常將
sharedWorker.js文件放在public目錄下,因?yàn)樵撃夸浵碌奈募粫?huì)經(jīng)過 Webpack、vite 處理,構(gòu)建后文件的路徑和名稱保持不變,確保SharedWorker能夠正確加載腳本文件。兼容性:
SharedWorker在現(xiàn)代瀏覽器中得到了廣泛支持,但在一些舊版本的瀏覽器中可能不支持。在使用時(shí),建議進(jìn)行兼容性檢查或使用 Polyfill 來確保在不同瀏覽器中的兼容性。優(yōu)缺點(diǎn)
? 無需服務(wù)器,支持復(fù)雜邏輯
? 兼容性有限(不支持 IE),調(diào)試?yán)щy
?? 需注意同源策略,本地測試需啟動(dòng)服務(wù)器。
常見的跨標(biāo)簽頁通信就是這四種,還有一些不常用的比如:postMessage 、ServiceWorker。 要么比較復(fù)雜,要么有明顯缺陷,在這里就不多展開??偨Y(jié)一下使用場景 ??
| 場景 | 推薦方案 | 原因 |
|---|---|---|
| 簡單數(shù)據(jù)同步 | localStorage / BroadcastChannel | 輕量且無需服務(wù)器 |
| 實(shí)時(shí)通信 | BroadcastChannel / WebSocket | 事件驅(qū)動(dòng)或服務(wù)器推送 |
| 跨域需求 | WebSocket | 支持跨域協(xié)議 |
| 復(fù)雜計(jì)算邏輯 | SharedWorker | 分擔(dān)主線程壓力 |
| 兼容性優(yōu)先 | localStorage + WebSocket | 覆蓋舊瀏覽器與跨域需求 |
以上就是Vue3實(shí)現(xiàn)跨標(biāo)簽頁通信的四種方式的詳細(xì)內(nèi)容,更多關(guān)于Vue3跨標(biāo)簽頁通信的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解如何在 vue 項(xiàng)目里正確地引用 jquery 和 jquery-ui的插件
本篇文章主要介紹了詳解如何在 vue 項(xiàng)目里正確地引用 jquery 和 jquery-ui的插件,具有一定的參考價(jià)值,有興趣的可以了解一下2017-06-06
Vue中計(jì)算屬性和監(jiān)聽屬性及數(shù)據(jù)的響應(yīng)式更新和依賴收集基本原理講解
computed是vue的配置選項(xiàng),它的值是一個(gè)對象,其中可定義多個(gè)計(jì)算屬性,每個(gè)計(jì)算屬性就是一個(gè)函數(shù),下面這篇文章主要給大家介紹了關(guān)于vue中計(jì)算屬性computed的詳細(xì)講解,需要的朋友可以參考下2023-03-03
vue-router 控制路由權(quán)限的實(shí)現(xiàn)
這篇文章主要介紹了vue-router 控制路由權(quán)限的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
v-distpicker地區(qū)選擇器組件使用實(shí)例詳解
代碼添加了一個(gè)vDistpickerHandle的事件處理函數(shù)對地區(qū)選擇器中的數(shù)據(jù)進(jìn)行處理,將數(shù)據(jù)存儲(chǔ)到form對象的相應(yīng)屬性中,方便數(shù)據(jù)提交,這篇文章主要介紹了v-distpicker地區(qū)選擇器組件使用,需要的朋友可以參考下2024-02-02
基于vue+canvas的excel-like組件實(shí)例詳解
a vue component,基于vue的表格組件,主要解決大數(shù)據(jù)量的表格渲染性能問題,使用canvas繪制表格,同時(shí)支持類似excel的批量選中,復(fù)制黏貼刪除,實(shí)時(shí)編輯等功能.這篇文章主要介紹了基于vue+canvas的excel-like組件,需要的朋友可以參考下2017-11-11
Vue 中 reactive創(chuàng)建對象類型響應(yīng)式數(shù)據(jù)的方法
在 Vue 的開發(fā)世界里,響應(yīng)式數(shù)據(jù)是構(gòu)建交互性良好應(yīng)用的基礎(chǔ),之前我們了解了ref用于定義基本類型的數(shù)據(jù),今天就來深入探討一下如何使用reactive定義對象類型的響應(yīng)式數(shù)據(jù),感興趣的朋友一起看看吧2025-02-02

