需求:
浏览器不同 tab 标签页之间是独立的, 如果要通信必须通过特殊手段来实现跨标签页通信。
1.StorageEvent 事件
当一个标签页 localStorage 变化时(sessionStorage 无效),同源下另一个或其他所有标签页使用 DOM2 监听 storage 事件监听,不能使用 DOM0 监听,最新 Chrome 不支持。
StorageEvent:当前页面使用的 storage 被其他页面修改时会触发 StorageEvent 事件。
事件在同一个域下的不同页面之间触发,即在 A 页面注册了 storge 的监听处理,只有在跟 A 同域名下的 B 页面操作 storage 对象,A 页面才会被触发 storage 事件
示例代码:
// 在一个标签页中设置localStorage
window.localStorage.setItem("sendMessage", "Hello,Bro!");// 在同源下另一个或所有的标签页下所有数据 监听storage 事件
window.addEventListener("storage", e => {console.log(e.key);console.log(e.oldValu);console.log(e.newValue);if (e.key === "sendMessage") {console.log(e.newValue); // Hello,Bro!}
});
事件对象包含以下属性:
2.window.open 配合 window.postMessage
otherWindow.postMessage(message, targetOrigin, [transfer]);
message:要发送的消息,可以是任意类型的数据。
targetOrigin:通过窗口的 origin 属性来指定哪些窗口能接收到消息事件,其值可以是字符串"_"(表示无限制)或者一个 URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配 targetOrigin 提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用 postMessage 传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的 origin 属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的 targetOrigin,而不是 _。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
transfer:可选的,是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
targetOrigin 值可以是以下任意一个:
一个 URI,表示该 URI 所表示的源。
示例代码:
// 在一个标签页中发送消息
const baidu = window.open("baidu.com");
baidu.postMessage("Hello,Bro!", "*");
// 在window.open()打开的另一个标签页中接受消息
window.addEventListener("message", event => {console.log("Received", event.data); // Received Hello,Bro!
});
3.BroadcastChannel(webworker 可用)
BroadcastChannel 接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信。通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。
BroadcastChannel 顾名思义 广播频道,这个 WEB API 设计用来跨标签页之间通信
属性
BroadcastChannel.name
频道名称,返回 DOMString。
事件处理程序
BroadcastChannel.onmessage()
,或 BroadcastChannel.addEventListener('message',callback)
事件处理器,用于定义当该对象上触发了 message 事件时要执行的函数。BroadcastChannel.onmessageerror()
,或 BroadcastChannel.addEventListener('messageerror', callback)
事件处理器,用于定义当该对象上触发了类型为 MessageError 的 MessageEvent 事件时要执行的函数。当接收到一条无法反序列化的消息时会触发此事件。
方法
BroadcastChannel.postMessage()
向所有监听了相同频道的 BroadcastChannel 对象发送一条消息,消息内容可以是任意类型的数据。BroadcastChannel.close()
关闭频道对象,告诉它不要再接收新的消息,并允许它最终被垃圾回收。
示例代码:
// 在一个标签页中发送消息
const channel = new BroadcastChannel("myChannel");
channel.postMessage("Hello,Bro!");
// 在另一个或其他所有标签页中接受同频道消息
const channel = new BroadcastChannel("myChannel");
channel.addEventListener("message", event => {console.log("Received", event.data); // Hello,Bro!
});
// 断开频道连接
channel.close();
4.SharedWorker(注意兼容性)
创建一个执行指定 url 脚本的共享 web worker。如果要使 SharedWorker 连接到多个不同的页面,这些页面必须是同源的(相同的协议、host 以及端口)。
示例代码:
// worker.js
onconnect = function (e) {var port = e.ports[0];port.addEventListener("message", function (e) {var workerResult = "Result: " + e.data;port.postMessage(workerResult);});port.start(); // 使用addEventListener 要手动加上. 如果使用onmessage则可以省略
};
// 在不同页面中创建共享 web worker
this.shareWorker = new SharedWorker("./worker.js");
// 接受信息
this.shareWorker.port.onmessage = e => {console.log(e.data);
};
// 发送信息,可以传递任何东西
this.shareWorker.port.postMessage({type: "notifyTab",payload: {}
});
5.其他一些偏方
IndexedDB 定时器轮询,cookie 定时器轮询,Websocket 等