浏览器跨标签页通信
浏览器跨标签页通信
- 1.什么是浏览器跨标签页通信?
- 2.浏览器跨标签页通信主要用在哪些需求?
- 3.LocalStorage或SessionStorage实现
- 4.cookie实现
- 5.indexedDB实现
- 6.Broadcast Channel API实现
- 7.window.postMessage()实现
- 8.SharedWorker实现
- 9.使用服务器端存储实现
- 9.1什么是websocket
- 9.2websocket特点:
- 9.3websocket结合服务器实现跨标签页通信思路:
- 9.4websocket结合服务器实现跨标签页通信代码:
- 10.总结
1.什么是浏览器跨标签页通信?
浏览器跨标签页通信是指在同一个浏览器窗口中的多个标签页之间进行数据交流和信息传递的过程。通常情况下,每个标签页都是一个独立的浏览器上下文,它们之间是相互隔离的,无法直接访问对方的数据或进行通信。
跨标签页通信的目的是允许这些相互隔离的标签页之间进行信息共享和交互。通过跨标签页通信,可以实现数据的共享、状态的同步、消息的传递等功能。
例如,在一个标签页中进行了某个操作,希望其他标签页能够及时获得相关的变化和通知,就需要使用跨标签页通信机制来实现这种交互。
2.浏览器跨标签页通信主要用在哪些需求?
浏览器跨标签页通信主要用于以下几种需求:
- 数据共享:
当多个标签页需要访问和共享相同的数据时,跨标签页通信可以用于在这些标签页之间传递数据,确保它们保持同步。 - 状态同步:
在一些应用中,可能会有多个标签页用于展示相同的应用状态或会话状态。通过跨标签页通信,可以实现状态的同步,使得在一个标签页中的操作能够即时反映到其他标签页上。 - 消息通知:
跨标签页通信可以用于实现在一个标签页中发送消息,然后其他标签页接收并展示这些消息的功能。 - 共享资源:
在某些场景下,可能需要在多个标签页之间共享某些资源,如网络连接、音频/视频播放器等。 - 多窗口管理:
对于一些具有多个窗口的应用,跨标签页通信可以用于实现窗口之间的联动和数据同步。
3.LocalStorage或SessionStorage实现
LocalStorage和SessionStorage同域共享,(如果多个标签页跨域了,那么数据将无法共享)。并且浏览器提供了storage事件来捕获存储事件。
新建两个页面pageA和pageB,利用localStorage实现两个页面之间的通信。
// pageA.html
<body>
<h1>pageA</h1>
</body>
<script>
window.addEventListener("storage", (e) => {
console.info("localStorage发生变化:", e)
})
</script>
// pageB.html
<body>
<h1>pageB</h1>
<button id="btnB">添加数据到localStorage</button>
</body>
<script>
let btnB = document.getElementById("btnB");
let num = 0;
btnB.addEventListener("click", () => {
localStorage.setItem("num", num++)
})
</script>
当我们点击pageB中的按钮时,会更改localStorage中的值。然后在pageA中的storage监听函数便会监听到localStorage发生变化。
pageA输出结果:
注意:pageA和pageB同源,即域名、端口、协议等都是相同的;使用storage事件监听localStorage变化。
4.cookie实现
我们都知道cookie可以用来存储数据,而且它是同源共享的,借助它的这些特点,我们就可以利用cookie实现多页面的通讯。
// pageA.html
<script>
setInterval(() => {
//加入定时器,让函数每一秒就调用一次,实现页面刷新
console.log("cookie",document.cookie)
}, 1000);
</script>
// pageB.html
<script>
let btnB = document.getElementById("btnB");
let num = 0;
btnB.addEventListener("click", () => {
document.cookie = `客户端B发送的消息:${num++}`
})
</script>
输出结果:
这种方式实现的原理非常简单,就是在需要接收消息的页面不断轮询去查询cookie,然后发送消息的页面将数据存储在cookie中,这样就实现了简单的数据共享。
5.indexedDB实现
IndexedDB 是浏览器提供的一个客户端数据库,可以在不同的标签页之间存储和读取数据。一个标签页可以将数据写入IndexedDB,其他标签页可以监听 IndexedDB 的变化事件或定时从 IndexedDB 中读取数据来实现数据的共享和状态的同步(与storage实现类似)。
6.Broadcast Channel API实现
Broadcast Channel API 允许不同标签页之间通过共享的通道进行消息广播和接收。一个标签页可以通过通道发送消息,其他订阅了相同通道的标签页可以接收到这些消息。
在发送消息的标签页中:
// 创建一个广播通道
const channel = new BroadcastChannel('myChannel');
// 发送消息
channel.postMessage('Hello from Tab 1');
在接收消息的标签页中:
// 创建一个广播通道
const channel = new BroadcastChannel('myChannel');
// 监听消息事件
channel.onmessage = function(event) {
const message = event.data;
console.log('Received message:', message);
};
7.window.postMessage()实现
Window.postMessage() 方法允许在不同的窗口或标签页之间安全地传递消息。通过调用postMessage() 方法并指定目标窗口的 origin,可以将消息发送到其他标签页,并通过监听 message 事件来接收消息。
在发送消息的标签页中:
// 监听消息事件
window.addEventListener('message', function(event) {
// 确保消息来自预期的源
if (event.origin !== 'http://example.com') {
return;
}
const message = event.data;
console.log('Received message:', message);
});
// 发送消息到其他标签页
const targetWindow = window.open('http://example.com/otherpage', '_blank');
targetWindow.postMessage('Hello from Tab 1', 'http://example.com');
在接收消息的标签页中:
// 监听消息事件
window.addEventListener('message', function(event) {
// 确保消息来自预期的源
if (event.origin !== 'http://example.com') {
return;
}
const message = event.data;
console.log('Received message:', message);
// 回复消息
event.source.postMessage('Hello from Other Tab', event.origin);
});
8.SharedWorker实现
我们都知道JavaScript是单线程的,单线程有好处也有坏处。为了弥补JS单线程的坏处,WebWorker随之被提出,它可以为JS创造多线程环境。
sharedWorker就是WebWorker中的一种,它可以由所有同源页面共享,利用这个特性,我们就可以使用它来进行多标签页之前的通信。
sharedWorker特点:
- 跨域不共享,即多个标签页不能跨域
- 使用port发送和接收消息
- 如果url相同,且是同一个js,那么只会创建一个sharedWorker,多个页面共享这个sharedWorker
新建一个worker.js,编写代码。
// worker.js
const set = new Set()
onconnect = event => {
const port = event.ports[0]
set.add(port)
// 接收信息
port.onmessage = e => {
// 广播信息
set.forEach(p => {
p.postMessage(e.data)
})
}
// 发送信息
port.postMessage("worker广播信息")
}
//pageA
<script>
const worker = new SharedWorker('./worker.js')
worker.port.onmessage = e => {
console.info("pageA收到消息", e.data)
}
</script>
//pageB
<script>
const worker = new SharedWorker('./worker.js')
let btnB = document.getElementById("btnB");
let num = 0;
btnB.addEventListener("click", () => {
worker.port.postMessage(`客户端B发送的消息:${num++}`)
})
</script>
9.使用服务器端存储实现
将需要共享的数据存储在服务器端,标签页之间通过与服务器进行通信来获取和更新数据。可以使用 AJAX、WebSocket 或其他网络通信技术来实现与服务器的数据交互。
注意:使用服务器端存储的方法可能需要进行网络请求,可能会涉及到延迟和带宽消耗。
下面以websocket为例:
9.1什么是websocket
websocket是一种网络通讯协议。我们都知道在使用HTTP协议的时候,我们与服务端都是通过发请求的方式进行通讯的,而且这种通讯只能由客户端发起。websocket协议就弥补了这一缺点,它是一个全双工通信的协议,意味着客户端和服务端可以互相通信,享受平等关系。
最简单列子就是聊天室,我们在聊天室里面可以收消息,也可以发消息,只要我们与服务端通过websocket建立好了连接。
9.2websocket特点:
- 保持连接状态,HTTP协议是无状态连接,即请求完毕后就会关闭连接。
- 全双工通信,客户端和服务端平等对待,可以互相通信。
- 建立在TCP协议之上
- 没有同源共享策略,即可实现跨域共享
9.3websocket结合服务器实现跨标签页通信思路:
使用websocket实现原理比较简单,假如我们pageA和pageB都与服务器建立了websocket连接,那么两个页面都可以实时接收服务端发来的消息,也可以实时向服务端发送消息。如果pageA更改了数据,那么向服务端发送一条消息或数据,服务端在将这条消息或数据发送给pageB即可,这样就简单实现了两个标签页之间的通信。
9.4websocket结合服务器实现跨标签页通信代码:
我们先来搭建一个简单的websocket服务器,用于pageA和pageB的连接,新建index.js文件。
初始化命令:
npm init -y
npm install --save ws
运行命令:node index.js
index.js:
// index.js
let WebSocketServer = require("ws").Server;
let wss = new WebSocketServer({ port: 3000 });
// 创建保存所有已连接到服务器的客户端对象的数组
let clients = [];
// 为服务器添加connection事件监听,当有客户端连接到服务端时,立刻将客户端对象保存进数组中。
wss.on("connection", function (client) {
console.log("一个客户端连接到服务器");
if (clients.indexOf(client) === -1) {
clients.push(client);
// 接收客户端发送的消息
client.on("message", function (msg) {
console.log("收到消息:" + msg);
// 将消息发送给非自己的客户端
for (let key of clients) {
if (key != client) {
key.send(msg.toString());
}
}
});
}
});
pageA:
// pageA
<script>
// 创建一个websocket连接
var ws = new WebSocket('ws://localhost:3000/');
// WebSocket连接成功回调
ws.onopen = function () {
console.log("websocket连接成功")
}
// 这里接受服务器端发过来的消息
ws.onmessage = function (e) {
console.log("服务端发送的消息", e.data)
}
</script>
pageB:
<script>
let btnB = document.getElementById("btnB");
let num = 0;
btnB.addEventListener("click", () => {
ws.send(`客户端B发送的消息:${num++}`);
})
// 创建一个websocket连接
var ws = new WebSocket('ws://localhost:3000/');
// WebSocket连接成功回调
ws.onopen = function () {
console.log("websocket连接成功")
}
</script>
当我们点击pageB中的按钮时,会通过websocket向服务端发送一条消息,服务端接收到这条消息之后,会将消息转发给pageA,这样pageA就得到了pageB传来的数据。
10.总结
- sessionstorage和localstorage
- cookie
- indexDB
- Broadcast Channel API
- window.postMessage()
- SharedWorker
- 服务器端存储+网络通信技术