场景:当涉及到同时打开多个tab页,操作一个tab,希望其他的tab也会同时进行更新状态。
原理就是前度的跨页面通信
一、【同源通信】LocalStorage
1 当 LocalStorage 变化时,会触发storage事件。
在需要改变的页面增加时间监听:
window.addEventListener('storage', function (e) {
if (e.key === 'ctc-msg') {
const data = JSON.parse(e.newValue);
const text = '[receive] ' + data.msg + ' —— tab ' + data.from;
console.log('[Storage I] receive message:', text);
}
});
2 调用 window.localStorage.setItem() 触发更新。
这里需要注意,当两次 setItem 更新的值一样时,监听方法是不会触发的。
二、【非同源通信】iframe
我们有两个不同域名的产品线,也希望它们下面的所有页面之间能无障碍地通信。那该怎么办呢?
要实现该功能,可以使用一个用户不可见的 iframe 作为“桥”。由于 iframe
与父页面间可以通过指定origin来忽略同源限制,因此可以在每个页面中嵌入一个 iframe
(例如:http://sample.com/bridge.html),而这些 iframe 由于使用的是一个
url,因此属于同源页面,其通信方式可以复用上面第一部分提到的各种方式。 页面与 iframe 通信非常简单,首先需要在页面中监听iframe 发来的消息,做相应的业务处理:
/* 业务页面代码 */
window.addEventListener('message', function (e) {
// …… do something
});
然后,当页面要与其他的同源或非同源页面通信时,会先给 iframe 发送消息:
/* 业务页面代码 */
window.frames[0].window.postMessage(mydata, '*');
复制代码其中为了简便此处将postMessage的第二个参数设为了’*’,你也可以设为 iframe 的 URL。 iframe
收到消息后,会使用某种跨页面消息通信技术在所有 iframe 间同步消息,例如下面使用的 Broadcast Channel:
/* iframe 内代码 */
const bc = new BroadcastChannel('AlienZHOU');
// 收到来自页面的消息后,在 iframe 间进行广播
window.addEventListener('message', function (e) {
bc.postMessage(e.data);
});
其他 iframe 收到通知后,则会将该消息同步给所属的页面:
/* iframe 内代码 */
// 对于收到的(iframe)广播消息,通知给所属的业务页面
bc.onmessage = function (e) {
window.parent.postMessage(e.data, '*');
};
下图就是使用 iframe 作为“桥”的非同源页面间通信模式图。