JS中BroadcastChannel實現(xiàn)瀏覽器標(biāo)簽頁通信
瀏覽器標(biāo)簽頁通信常用于列表頁進(jìn)入詳情頁所進(jìn)行的標(biāo)簽頁間通信的情況,實際使用例如博客頁面的列表和文章編輯頁面、音樂網(wǎng)站的列表和音樂播放詳情等。
window.open()實現(xiàn)
使用常用的window.open()API也可以實現(xiàn),但會存在以下問題:
- 打開新頁面時瀏覽器標(biāo)簽頁焦點也會跳轉(zhuǎn)到新頁面(如果沒有標(biāo)簽頁焦點不變的需求可以忽略不計);
- 打開新頁面導(dǎo)致新頁面全局刷新(多頁應(yīng)用或跳轉(zhuǎn)的新頁面內(nèi)容較少可忽略不計);
BroadcastChannel實現(xiàn)
BroadcastChannel 是 Web API 里用于在同源的不同瀏覽器上下文(像不同的窗口、標(biāo)簽頁、iframe 等)間進(jìn)行通信的機(jī)制,因此可以規(guī)避以上兩個問題:
實現(xiàn)過程
創(chuàng)建兩個路由頁面
- 列表頁
/ - 詳情頁
/detail
列表頁
<template>
<div class="table-box">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="username" label="用戶名" />
<el-table-column prop="sex" label="性別" />
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="scope">
<el-button
link
type="primary"
size="small"
@click="handleClick(scope.row)"
>
詳情
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { ref } from "vue";
import { userList } from "@/utils/data";
const handleClick = async (row) => {
// channel通信
const channel = new BroadcastChannel("user_detail");
const tabCount = localStorage.getItem("TAB_COUNT");
if (!tabCount || tabCount === "1") {
await localStorage.setItem("TAB_COUNT", "2");
await sessionStorage.setItem("TAB_ID", row.id);
window.open("/detail", "user_detail");
} else {
channel.postMessage(row.id);
}
};
const tableData = ref(userList);
</script>
詳情頁
<template>
<el-descriptions
class="margin-top"
title="用戶信息表"
:column="3"
size="large"
border
>
<template #extra>
<el-button type="primary" @click="goBack">返回</el-button>
</template>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon :style="iconStyle">
<user />
</el-icon>
用戶名
</div>
</template>
{{ curUser.username }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon :style="iconStyle">
<iphone />
</el-icon>
年齡
</div>
</template>
{{ curUser.age }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon :style="iconStyle">
<location />
</el-icon>
籍貫
</div>
</template>
{{ curUser.city }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon :style="iconStyle">
<tickets />
</el-icon>
性別
</div>
</template>
{{ curUser.sex }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon :style="iconStyle">
<office-building />
</el-icon>
住址
</div>
</template>
{{ curUser.address }}
</el-descriptions-item>
</el-descriptions>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { userList } from "@/utils/data";
const route = useRoute();
const initialUser = {
date: "",
username: "",
sex: "",
age: 18,
city: "",
address: "",
id: "",
};
const curUser = ref({ ...initialUser });
const goBack = async () => {
await localStorage.setItem("TAB_COUNT", "1");
await sessionStorage.removeItem("TAB_ID");
window.close();
};
const iconStyle = {
fontSize: "20px",
color: "#409eff",
};
const channel = new BroadcastChannel("user_detail");
channel.addEventListener("message", (event) => {
console.log("接收到消息:", event.data);
sessionStorage.removeItem("TAB_ID");
const curUserId = event.data;
const user = userList.find((user) => user.id === curUserId);
if (user) {
curUser.value = user;
}
});
onMounted(() => {
const curUserId = sessionStorage.getItem("TAB_ID");
if (curUserId) {
const user = userList.find((user) => user.id === curUserId);
if (user) {
curUser.value = user;
}
}
// 監(jiān)聽頁面卸載事件
window.addEventListener("unload", async () => {
await localStorage.setItem("TAB_COUNT", "1");
await sessionStorage.removeItem("TAB_ID");
});
});
</script>
實現(xiàn)效果

實現(xiàn)原理
使用BroadcastChannel創(chuàng)建通道進(jìn)行瀏覽器標(biāo)簽頁通信,利用瀏覽器本地緩存記錄標(biāo)簽頁打開數(shù)量,如果數(shù)量為1(僅有列表頁,沒有詳情頁),則使用window.open打開;反之如果數(shù)量為2,則使用BroadcastChannel通道發(fā)送消息實現(xiàn)頁面數(shù)據(jù)更新;
BroadcastChannel和postMessage區(qū)別
相同點:
- 都可在不同頁面之間,進(jìn)行信息通訊
不同點:
- BroadcastChannel只可用于同源的不同頁面;
- postmessage可以任何源
1.BroadcastChannel使用方法
// 實例BroadcastChannel
const myChannel = new BroadcastChannel('aa');
// 發(fā)送信息
myChannel.postMessage('發(fā)送的某些數(shù)據(jù)');
myChannel.onmessage = function(e){
// 接收到的消息
console.log(e.data);
}
// 關(guān)閉鏈接
myChannel.close();
2.postMessage使用方法
//給其他源發(fā)送postMessage
otherWindow.postMessage(message, targetOrigin, [transfer]);
****解釋********
otherWindow:其他窗口的一個引用,比如 iframe 的 contentWindow 屬性、執(zhí)行 window.open 返回的窗口對象、或者是命名過或數(shù)值索引的 window.frames
message:將要發(fā)送到其他 window的數(shù)據(jù)。
targetOrigin:指定哪些窗口能接收到消息事件,其值可以是 *(表示無限制)或者一個 URI。
transfer:可選,是一串和 message 同時傳遞的 Transferable 對象。這些對象的所有權(quán)將被轉(zhuǎn)移給消息的接收方,而發(fā)送一方將不再保有所有權(quán)。
*****************
// 其他源的頁面,添加addEventlistener監(jiān)聽message
window.addEventListener('message', function (e) { // 監(jiān)聽 message 事件
messageEle.innerHTML = "從"+ e.origin +"收到消息: " + e.data;
});到此這篇關(guān)于JS中BroadcastChannel實現(xiàn)瀏覽器標(biāo)簽頁通信的文章就介紹到這了,更多相關(guān)JS BroadcastChannel瀏覽器標(biāo)簽頁通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js設(shè)計模式之結(jié)構(gòu)型享元模式詳解
這篇文章主要為大家詳細(xì)介紹了js設(shè)計模式之結(jié)構(gòu)型享元模式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
跟我學(xué)Nodejs(三)--- Node.js模塊
這是本系列的第三篇文章了,前面2篇網(wǎng)友們反饋回來不少的消息,加上最近2天比較忙,一直沒來得及整理,周末了,趕緊給大家整理下發(fā)出來,本文講的是node.js模塊2014-05-05
Javascript中查找不以XX字符結(jié)尾的單詞示例代碼
我在寫這篇文章之前花了2個多小時在弄正則表達(dá)式,下為大家介紹下具體的實現(xiàn)思路,感興趣的朋友可以參考下2013-10-10

