Vue3實現(xiàn)跨標簽頁通信的四種方式
我們假設我們需求是需要新開一個頁面,并且這兩個頁面需要通信,就可以使用到以下的通信方式
1. localStorage+storage事件
原理 :利用瀏覽器同源標簽頁共享的
localStorage
存儲數(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(() => { // 標簽頁 Home:寫入數(shù)據(jù) localStorage.setItem("message", "Home Page"); }); </script>
localStorage
是 HTML5 新增的一個會話存儲對象,它允許網(wǎng)頁在瀏覽器中存儲鍵值對形式的數(shù)據(jù),并且這些數(shù)據(jù)不會隨著頁面的關閉而消失,除非手動刪除。
<!-- src/views/About.vue --> <template> <div> <h1>About Page</h1> </div> </template> <script setup> import { onMounted } from "vue"; onMounted(() => { // 標簽頁 About:監(jiān)聽變化 window.addEventListener("storage", (event) => { if (event.key === "message") { console.log("收到消息:", event.newValue); } }); }); </script>
這樣當頁面 Home 設置 localStorage 的時候就會被監(jiān)聽到,達到一個不同標簽的通信效果。
優(yōu)缺點
? 簡單易用,無需服務器
? 無法監(jiān)聽當前標簽頁修改,數(shù)據(jù)需序列化傳輸
?? 注意:sessionStorage
無法觸發(fā)跨標簽事件,因其數(shù)據(jù)僅窗口級別共享。那么有人就會有問題了,既然
localStorage
可以,那sessionStorage
可不可以呢?答案是不行的。因為
storage
事件的觸發(fā)條件是:當localStorage
或sessionStorage
中的數(shù)據(jù)發(fā)生變化時,除了觸發(fā)變化的窗口(或標簽頁)之外,同一源下的其他窗口(或標簽頁)會收到storage
事件。由于
sessionStorage
的數(shù)據(jù)是窗口(或標簽頁)級別的,不同標簽頁之間的sessionStorage
是相互隔離的,一個標簽頁對sessionStorage
的修改不會影響其他標簽頁,因此sessionStorage
的變化不會觸發(fā)其他標簽頁的storage
事件。
2. BroadcastChannel API
原理 :
BroadcastChannel
API 是 HTML5 新增的一種在瀏覽器中實現(xiàn)跨窗口、跨標簽頁甚至跨工作線程進行通信的機制。它提供了一種簡單而有效的方式,讓同源的不同瀏覽上下文(如不同窗口、標簽頁、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 = () => { // 標簽頁 Home:發(fā)送消息 // 1. 創(chuàng)建 BroadcastChannel 實例 // 要使用 BroadcastChannel,首先需要創(chuàng)建一個 BroadcastChannel 實例,并指定一個頻道名稱。頻道名稱是一個字符串,用于標識不同的通信頻道。這里的頻道就是 "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)代項目中常用的一種通信方式,利用 BroadcastChannel Api 在兩個頁面分別發(fā)送與監(jiān)聽
優(yōu)缺點
? 實時性強,代碼簡潔
? 不支持 IE 瀏覽器
?? 需注意頻道名稱全局唯一,避免沖突。
3. WebSocket
原理 :通過服務器中轉(zhuǎn)消息,實現(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">關閉連接</el-button> <ul> <li v-for="(message, index) in receivedMessages" :key="index"> {{ message }} </li> </ul> </div> </template> <script setup> import { ref } from "vue"; // 存儲 WebSocket 實例 const socket = ref(null); // 存儲接收到的消息 const receivedMessages = ref([]); // 連接 WebSocket const connectWebSocket = () => { // 創(chuàng)建 WebSocket 實例,這里以 echo.websocket.org 為例,它是一個公共的 WebSocket 測試服務器,省去了自己搭建服務器的麻煩 socket.value = new WebSocket("wss://echo.websocket.org"); // WebSocket 連接成功時觸發(fā) socket.value.onopen = () => { console.log("WebSocket 連接成功"); receivedMessages.value.push("WebSocket 連接成功"); }; // 接收到服務器消息時觸發(fā) socket.value.onmessage = (event) => { console.log("接收到消息:", event.data); receivedMessages.value.push(event.data); }; // WebSocket 連接關閉時觸發(fā) socket.value.onclose = () => { console.log("WebSocket 連接已關閉"); receivedMessages.value.push("WebSocket 連接已關閉"); socket.value = null; }; // WebSocket 發(fā)生錯誤時觸發(fā) socket.value.onerror = (error) => { console.error("WebSocket 發(fā)生錯誤:", error); receivedMessages.value.push("WebSocket 發(fā)生錯誤"); }; }; // 發(fā)送消息到服務器 const sendMessage = () => { if (socket.value) { const message = "Hello, WebSocket!"; socket.value.send(message); receivedMessages.value.push(`發(fā)送消息: ${message}`); } }; // 關閉 WebSocket 連接 const closeWebSocket = () => { if (socket.value) { socket.value.close(); } }; </script>
實際項目中 WebSocket 的服務器一般由后端搭建,這里用一個公共的測試服務器為例
優(yōu)缺點
? 支持跨域,實時性高
? 需維護服務器,復雜度高
?? 實際項目需自建服務器,確保安全性。
4. SharedWorker
原理 :SharedWorke r是一種特殊類型的Worker,它可以在多個瀏覽器上下文(如窗口、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>響應內(nèi)容</div> </template> <div>{{ response }}</div> </el-card> </el-card> </template> <script setup> import { ref, onMounted } from "vue"; // 創(chuàng)建 SharedWorker 實例,指定工作線程腳本文件路徑 const worker = new SharedWorker("sharedWorker.js"); // 存儲接收到的響應 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 接收到響應:", newResponse); // 更新響應內(nèi)容 response.value = newResponse; }; // 啟動端口通信 worker.port.start(); }); </script>
// sharedWorker.js 文件,需要放在 public // 創(chuàng)建一個消息通道,用于在不同上下文和工作線程之間通信 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ā)送消息的端口回復消息 const response = `SharedWorker 已收到消息: ${message}`; port.postMessage(response); }; };
注意:
同源策略:
SharedWorker
遵循同源策略,即sharedWorker.js
文件必須與主頁面文件同源(相同的協(xié)議、域名和端口)。如果直接通過file://
協(xié)議打開 HTML 文件,會因同源策略限制而導致SharedWorker
無法正常工作。如果想在本地用html文件進行測試,需要啟動一個服務器,Live Serve 可以滿足需求。文件路徑:在 Vue 項目中,通常將
sharedWorker.js
文件放在public
目錄下,因為該目錄下的文件不會經(jīng)過 Webpack、vite 處理,構(gòu)建后文件的路徑和名稱保持不變,確保SharedWorker
能夠正確加載腳本文件。兼容性:
SharedWorker
在現(xiàn)代瀏覽器中得到了廣泛支持,但在一些舊版本的瀏覽器中可能不支持。在使用時,建議進行兼容性檢查或使用 Polyfill 來確保在不同瀏覽器中的兼容性。優(yōu)缺點
? 無需服務器,支持復雜邏輯
? 兼容性有限(不支持 IE),調(diào)試困難
?? 需注意同源策略,本地測試需啟動服務器。
常見的跨標簽頁通信就是這四種,還有一些不常用的比如:postMessage
、ServiceWorker
。 要么比較復雜,要么有明顯缺陷,在這里就不多展開。總結(jié)一下使用場景 ??
場景 | 推薦方案 | 原因 |
---|---|---|
簡單數(shù)據(jù)同步 | localStorage / BroadcastChannel | 輕量且無需服務器 |
實時通信 | BroadcastChannel / WebSocket | 事件驅(qū)動或服務器推送 |
跨域需求 | WebSocket | 支持跨域協(xié)議 |
復雜計算邏輯 | SharedWorker | 分擔主線程壓力 |
兼容性優(yōu)先 | localStorage + WebSocket | 覆蓋舊瀏覽器與跨域需求 |
以上就是Vue3實現(xiàn)跨標簽頁通信的四種方式的詳細內(nèi)容,更多關于Vue3跨標簽頁通信的資料請關注腳本之家其它相關文章!
相關文章
Vue中@keyup.enter?@v-model.trim的用法小結(jié)
這篇文章主要介紹了Vue中@keyup.enter?@v-model.trim的用法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-12-12Vue.js 實現(xiàn)微信公眾號菜單編輯器功能(二)
這篇文章主要介紹了Vue.js 實現(xiàn)微信公眾號菜單編輯器功能,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧2018-05-05基于vue-cli vue-router搭建底部導航欄移動前端項目
這篇文章主要介紹了基于vue-cli vue-router搭建底部導航欄移動前端項目,項目中主要用了Flex布局,以及viewport相關知識,已達到適應各終端屏幕的目的。需要的朋友可以參考下2018-02-02vue 解決在微信內(nèi)置瀏覽器中調(diào)用支付寶支付的情況
這篇文章主要介紹了vue 解決在微信內(nèi)置瀏覽器中調(diào)用支付寶支付的情況,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11vue根據(jù)權限動態(tài)渲染按鈕、組件等的函數(shù)式組件實現(xiàn)
這篇文章主要介紹了vue根據(jù)權限動態(tài)渲染按鈕、組件等的函數(shù)式組件實現(xiàn)方式,具有很好的參考價值,希望杜大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11Vue結(jié)合原生js實現(xiàn)自定義組件自動生成示例
這篇文章主要介紹了Vue結(jié)合原生js實現(xiàn)自定義組件自動生成示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01