1.localStorage实现通信
借助localStorage实现标签页之间通信在实际项目中使用的很多,因为它操作简单,易于理解。如果你还不是早localStorage的用法,那你一定得恶补了。
localStorage的特点:
- 同域共享存储空间
- 持久化将数据存储来浏览器
- 提供事件监听localStorage变化
这里我们需要重点关注同域共享,如果多个标签页跨域了,那么数据将无法共享。
代码演示:
我们新建两个页面pageA和pageB,利用localStorage实现两个页面之间的通信。
示例代码:
pageA
// pageA.html <body> <h1>pageA</h1> </body> <script> window.addEventListener("storage", (e) => { console.info("localStorage发生变化:", e) }) </script>
pageB
// 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中不仅可以拿到改变后的值,还可以拿到改变之前的值。通过这种方式,我们就可以将两个页面的数据进行同步了。
注意点:
- pageA和pageB同源,即域名、端口、协议等都是相同的。
- 使用storage事件监听localStorage变化
当然,如果你只是需要两个页面之间数据共享,那么可以不使用storage监听方法,直接通过localStorage.getItem()获取即可。
2.使用websocket
websocket是一种网络通讯协议。我们都知道在使用HTTP协议的时候,我们与服务端都是通过发请求的方式进行通讯的,而且这种通讯只能由客户端发起。websocket协议就弥补了这一缺点,它是一个全双工通信的协议,意味着客户端和服务端可以互相通信,享受平等关系。
最简单列子就是聊天室,我们在聊天室里面可以收消息,也可以发消息,只要我们与服务端通过websocket建立好了连接。
websocket特点:
- 保持连接状态,HTTP协议是无状态连接,即请求完毕后就会关闭连接。
- 全双工通信,客户端和服务端平等对待,可以互相通信。
- 建立在TCP协议之上
- 没有同源共享策略,即可实现跨域共享
通过以上websocket的特点,我们再来思考如何利用websocket实现多标签页通信?
其实实现原理页比较简单,假如我们pageA和pageB都与服务器建立了websocket连接,那么连个页面都可以实时接收服务端发来的消息,也可以实时向服务端发送消息。如果pageA更改了数据,那么向服务端发送一条消息或数据,服务端在将这条消息或数据发送给pageB即可,这样就简单实现了两个标签页之间的通信。
原理有点类似于”中介“,我们可以通过中介来进行沟通。
代码演示:
我们先来搭建一个简单的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传来的数据。
pageA输出结果:
总体来说,原理很简单,只是需要了解websocket。通常情况下,我们不建议使用websocket来进行多标签页通信,因为这回增加服务器的负担。
3.SharedWorker
我们都知道JavaScript是单线程的,单线程有好处也有坏处。为了弥补JS单线程的坏处,webWorker随之被提出,它可以为JS创造多线程环境。如果还不了解webWorker的可以去官网初步了解一下。
sharedWorker就是webWorker中的一种,它可以由所有同源页面共享,利用这个特性,我们就可以使用它来进行多标签页之前的通信。
sharedWorker特点:
- 跨域不共享,即多个标签页不能跨域
- 使用port发送和接收消息
- 如果url相同,且是同一个js,那么只会创建一个sharedWorker,多个页面共享这个sharedWorker
其实它和我们的webSocket实现多页面通讯的原理很类似,都是发送数据和接收数据这样的步骤,shardWorker就好比我们的webSocket服务器。
代码演示:
新建一个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>
上面的代码就是一个最简单的sharedWorker的应用,我们在pageA页面中初始化了sharedWorker,并且设置了接收消息的监听函数,当sharedWorker初始化完成之后,pageA便会接收到一条消息,如下图:
后我们在pageB中同样初始化了sharedWorker的示例,点击按钮广播消息,此时pageA便可以收到消息,是不是和websocket的原理很像啊。
pageA输出结果:
调试sharedWorker:
我们如何查看当前是运行的哪个sharedWorker呢?可以在浏览时输入:chrome://inspect。
找到sharedWorker选项,就可以看到运行的sharedWorker,如下图:
兼容性查看:
总结:
sharedWorker的原理和websocket有点类似,都是广播和接收的原理,但是它也有一些缺点,比如调试不太方便、兼容性不太好。所以使用的时候一定要结合实际情况使用。
4.使用cookie + setInterval
我们都知道cookie可以用来存储数据,而且它是同源共享的,借助它的这些特点,我们就可以利用cookie实现多页面的通讯。
cookie特点:
- 跨域不共享
- 具有存储空间限制
- 请求会自动携带cookie
示例代码:
pageA
<script> setInterval(() => { //加入定时器,让函数每一秒就调用一次,实现页面刷新 console.log("cookie",document.cookie) }, 1000); </script>
pageB
<script> let btnB = document.getElementById("btnB"); let num = 0; btnB.addEventListener("click", () => { document.cookie = `客户端B发送的消息:${num++}` }) </script>
输出结果:
这种方式实现的原理非常简单,就是在需要接收消息的页面不断轮询去查询cookie,然后发送消息的页面将数据存储在cookie中,这样就实现了简单的数据共享。
总结
这里介绍了4中实现浏览器多标签页之前通讯的方法,它们优缺点也有优点,有的操作简单,有的已于理解等等,需要根据实际场景选择不一样的方法。
想要视频学习,可以移步B站:小猪课堂