跨窗口通信
更新时间:2024-05-04阅读整篇大约2分钟
BroadcastChannel
BroadcastChannel通过namespace
来区分不同的通信频道,允许同源下的任意窗口,frame 等之间相互通信
示例
ts
const channel = new BroadcastChannel('channel_test_1');
channel.addEventListener('message', e => {
console.log(e);
});//监听消息
channel.postMessage('hello world !');//发送消息
channel.close();//销毁
也可以删除掉监听事件,以此达到销毁目的,让其内存自动被回收。
发送和监听不能为同一个实例,多个实例通过相同的namespace
来使用同一个频道
Service Worker
使用Service Worker来实现窗口通信,在首次访问网页时,navigator.serviceWorker.controller
会为null,需要刷新页面才能够正常进行页面通信,具体的一些坑见ServiceWorker那片文章
ts
//sw.js
self.addEventListener('message', e => {
e.waitUntil(
// 对所有页面发送消息
self.clients.matchAll().then(clients => {
if (!clients || clients.length === 0) {
return;
}
clients.forEach(function (client) {
client.postMessage(e.data);
});
})
);
});
主要想法也是通过一个type(namespace)来区分不同频道
ts
export const useServiceWorker = () => {//这个只需要在类似入口文件处执行一次就行
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(res => {
for (const sw of res) {
sw.unregister();
}
navigator.serviceWorker.register('./sw.js');
});
}
};
export const useSendMessage = (namespace, data) => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(_ => {
navigator.serviceWorker.controller.postMessage({
namespace,
data,
});
});
}
};
export const useReceiveMessage = (namespace, cb) => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.addEventListener('message', e => {
if (e.data.namespace !== namespace) return;
cb(e.data.data);
});
}
};