页面之间的通信
JavaScript 是可以监控 localStorage
值的变化的。现代浏览器提供了一个名为 storage
的事件,当同一源下的其他窗口或标签页修改了 localStorage 时,这个事件会在当前窗口触发。监听 storage
事件可以实现实时监听 localStorage 的变化。
下面是如何监听 localStorage 变化的基本示例:
window.addEventListener('storage', function(event) {
if (event.storageArea === localStorage) { // 确保事件来自localStorage
if (event.key) { // key存在表示有项被修改、添加或删除
console.log('Key "%s" was changed from "%s" to "%s"',
event.key,
event.oldValue,
localStorage[event.key]);
} else { // 如果key不存在,则可能是整个localStorage被清除
console.log('The entire localStorage was cleared');
}
}
}, false);
请注意,storage
事件不会在触发改变的同一个窗口或标签页中触发,而是会在同一源下的其他打开的窗口或标签页中触发。这是因为 localStorage 在同源策略下是共享的,所以当一个窗口修改了 localStorage,其他所有相同源的窗口都能感知到这个变化。
此外,storage
事件对象提供了如下属性:
event.key
: 被修改的键名。event.oldValue
: 键值修改前的旧值,如果键被删除则为 null
。event.newValue
: 键值修改后的值,如果键被删除也会是 null
。event.url
: 触发改变的文档的 URL。event.storageArea
: 修改数据的 Storage 对象引用,通常是 localStorage
。然而,如果你想在一个窗口内部实时监听自身的 localStorage 变化,单纯依赖浏览器提供的 storage
事件是不够的,需要自行封装函数或利用 MutationObserver 等手段,但这并非标准做法,而且可能受到限制或无法稳定工作。在单窗口内实时监听 localStorage 通常需要在 setItem 等方法上进行包裹或替换,以便在调用时同步触发相应的事件。
对于浏览器标签页间的通信,以下是几种可行的方法:
LocalStorage/SessionStorage
通过监听 storage
事件,可以在不同的浏览器标签页间共享数据。当一个标签页修改了 localStorage
或 sessionStorage
,其他同源标签页会接收到 storage
事件通知,并可以从事件对象中获取变化的信息。
window.addEventListener('storage', function(event) {
if (event.key) {
console.log('Key "%s" changed to "%s"', event.key, localStorage[event.key]);
}
});
// 设置数据
localStorage.setItem('message', 'Hello from another tab');
Broadcast Channel API
使用 BroadcastChannel
接口可以创建一个命名的通道,让同源的多个浏览器上下文(如标签页、iframe 等)能够互相通信。
const channel = new BroadcastChannel('my-channel');
// 发送消息
channel.postMessage({ type: 'hello', data: 'From one tab' });
// 接收消息
channel.addEventListener('message', function(event) {
console.log('Received message:', event.data);
});
WebSockets
利用 WebSocket 技术,所有打开的标签页都可以连接到同一个服务器,通过服务器作为中介转发消息。
var socket = new WebSocket('ws://example.com/mychannel');
// 发送消息
socket.send(JSON.stringify({ message: 'Hello from one tab' }));
// 接收消息
socket.onmessage = function(event) {
console.log('Received via WebSocket:', JSON.parse(event.data));
};
Cookies + setInterval
虽然不是理想的方案,但是也可以通过定时检查 Cookie 值的变化来间接实现通信,但这通常效率较低且不适合频繁通信。
同源窗口间自定义事件
在同源的两个窗口之间,可以通过 window.postMessage
实现直接通信。
// 发送消息的窗口
otherWindow.postMessage('Hello from another tab', 'http://example.com');
// 接收消息的窗口
window.addEventListener('message', function(event) {
if (event.origin === 'http://example.com') {
console.log('Received message:', event.data);
}
});
选择哪种方式取决于具体的业务需求和技术背景。其中,Broadcast Channel API 和 window.postMessage 方法尤其适用于浏览器标签页间的直接通信。