使用背景
- iframe 嵌入多个页签,页签之间通讯
- a页面打开b页面,b页面提交了需要刷新a页面
1、onstorage
WindowEventHandlers.onstorage 属性包含一个在 storage 事件触发时运行的事件处理程序。当更改存储时会触发事件处理程序。
document.getElementById('l-btn').onclick = function () { localStorage.setItem('storage1', Date.now()) }
window.onstorage = function(e) {
console.log(`The ${e.key} key has been changed from ${e.oldValue} to ${e.newValue} .`);
};
2、open & opener
当我们 系统中通过 window.open 打开一个新页面时,window.open 方法会返回一个被打开页面的引用,而被打开页面则可以通过 window.opener 获取到打开它的页面的引用(当然这是在没有指定noopener的情况下)
window.opener.postMessage(data);
window.addEventListener('message', function (e) {
});
</script>
3、BroadCast Channel
BroadcastChannel 接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。它允许同源的不同浏览器窗口,Tab页,frame或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。
// 创建
const broadcastChannel = new BroadcastChannel('channelName');
// 监听消息
broadcastChannel.onmessage = function(e) {
console.log('监听消息:', e.data);
};
// 发送消息
broadcastChannel.postMessage('测试:传送消息');
// 关闭
broadcastChannel.close();
4、Service Worker
Service workers 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。
Service Worker 是一个可以长期运行在后台的 Worker,能够实现与页面的双向通信。多页面共享间的 Service Worker 可以共享,将 Service Worker 作为消息的处理中心(中央站)即可实现广播效果。
//-----./index.html
<div id="app"></div>
<button id="tab">新开 Tab</button>
<button id="l-btn">发送消息</button>
<script>
/* 判断当前浏览器是否支持serviceWorker */
if ('serviceWorker' in navigator) {
/* 当页面加载完成就创建一个serviceWorker */
window.addEventListener('load', function () {
/* 创建并指定对应的执行内容 */
/* scope 参数是可选的,可以用来指定你想让 service worker 控制的内容的子目录。在这个例子里,我们指定了 '/',表示 根网域下的所有内容。这也是默认值。*/
navigator.serviceWorker.register('./serviceWorker.js', { scope: './' })
.then(function (registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(function (err) {
console.log('ServiceWorker registration failed: ', err);
});
});
// 监听消息
navigator.serviceWorker.addEventListener('message', function (e) {
const data = e.data;
console.log('我接受到消息了:', data);
});
document.getElementById('l-btn').onclick = function () {
navigator.serviceWorker.controller && navigator.serviceWorker.controller.postMessage('测试,传送消息,我发送消息啦。。。');
};
}
</script>
//-----./serviceWorker.js
/* 监听安装事件,install 事件一般是被用来设置你的浏览器的离线缓存逻辑 */
this.addEventListener('install', function (event) {
/* 通过这个方法可以防止缓存未完成,就关闭serviceWorker */
event.waitUntil(
/* 创建一个名叫V1的缓存版本 */
caches.open('v1').then(function (cache) {
/* 指定要缓存的内容,地址为相对于跟域名的访问路径 */
return cache.addAll(['./index.html']);
})
);
});
/* 注册fetch事件,拦截全站的请求 */
this.addEventListener('fetch', function (event) {
event.respondWith(
// magic goes here
/* 在缓存中匹配对应请求资源直接返回 */
caches.match(event.request)
);
});
/* 监听消息,通知其他 Tab 页面 */
this.addEventListener('message', function(event) {
this.clients.matchAll().then(function(clients) {
clients.forEach(function(client) {
// 这里的判断目的是过滤掉当前 Tab 页面,也可以使用 visibilityState 的状态来判断
if(!client.focused) {
client.postMessage(event.data)
}
})
})
})
5、SharedWorker
SharedWorker 接口代表一种特定类型的 worker,可以从几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。它们实现一个不同于普通 worker 的接口,具有不同的全局作用域, SharedWorkerGlobalScope。
- Shared Worker 在实现跨页面通信时的,它无法主动通知所有页面,需要刷新页面或者是定时任务来检查是否有新的消息。在例子中我是手动刷新的,当然可以使用 setInterval 来定时刷新
// 创建共享线程对象
let worker = new SharedWorker("./sharedWorker.js");
// 手动启动端口
worker.port.start();
// 处理从 worker 返回的消息
worker.port.onmessage = function (val) {
...
};
详情见: 我知道的前端跨页面通信
欢迎关注我的前端自检清单,我和你一起成长