前言

我们都知道浏览器是可以打开很多标签页的,如果每个标签页代表的是单独的一个网站,那么这些标签页之间肯定是不能通信的,如果能通信那估计我们都得凉凉。但是在很多情况下,浏览器中的很多标签页都属于某一个网站,而且这些标签页之间会使用一些相同的数据,这个时候我们就需要让这些标签页的数据都保持同步。

比如很多博客网站,点击文章列表通常是打开一个新的标签页进入文章详情页,那么如果我们在文章详情页点赞、评论等操作,而文章列表页也使用了这些数据,这个时候我们需要保持两边的数据一致,衍生出来就是详情页改了数据,需要让列表页知道。

总结来看:在某些情况下,实现多标签页之间通信是必要的!

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中实现浏览器多标签页之前通讯的方法,它们优缺点也有优点,有的操作简单,有的已于理解等等,需要根据实际场景选择不一样的方法。

实现方式 优缺点
localStorage 优点: 操作简单,易于理解。缺点: 存储大小限制只能监听非己页面跨域不共享 (总体来说较为推荐
websocket 优点: 理论上可是实现任何数据共享跨域共享 缺点: 需要服务端配合增加服务器压力上手不易 (总体不推荐
sharedWorker 优点: 理论上可以实现任何数据共享性能较好 缺点: 跨域不共享调试不方便兼容性不好 (总体推荐一般
cookie 优点: 兼容性好易于上手和理解 缺点: 有存储大小限制轮询消耗性能发请求会携带cookie (总体不推荐

实现浏览器多标签页通信相关推荐

  1. mac下chrome浏览器的标签页、进程和内存分配

    因为最近要解决网页经常崩溃的问题,所以去研究了一下chrome浏览器的标签页和进程的关系,以及标签页对应进程的内存分配. 标签页和进程的对应关系 当chrome浏览器开启但是没有任何一个标签页的时候, ...

  2. ios开发跳转safari_阻止iOS Web APP中点击链接跳转到Safari 浏览器新标签页

    最近为了更好地接触移动Web 开发狠心购买了一台ipad mini(之前一直都是借同学的,借多了就不好意思了).拿来调试DeveMobile 与EaseMobile 主题 时候发现了不少问题,现在在一 ...

  3. WPF自适应可关闭的TabControl 类似浏览器的标签页

    原文:WPF自适应可关闭的TabControl 类似浏览器的标签页 效果如图: 虽然说是自适应可关闭的TabControl,但TabControl并不需要改动,不如叫自适应可关闭的TabItem. 大 ...

  4. 前端如何设置浏览器网页标签页前的小图标favicon.ico

    前端如何设置浏览器网页标签页前的小图标favicon.ico 步骤1: 将小图标favicon.ico文件(或者普通的icon小图片)放在项目的public或者static目录下 步骤2: index ...

  5. 在浏览器的标签页显示网站标志图标

    一.在浏览器的标签页显示网站标志图标 我们通常希望将浏览器里的Tab选项卡的图标换成自己网站的logo图片,这样看起来更真实和有信任感,可以在<head></head>中添加l ...

  6. Chrome浏览器新标签页设置首页主页修改添加网站Infinity插件好用

    Infinity new tab 是一款美观实用的chrome 新标签页.最常访问的网站添加,修改,删除网址都有,每日一图,云备份等功能都具备.是一款基于html5的Chrome扩展程序,它重新定义了 ...

  7. yandex禁止java script_Yandex最新版本浏览器新标签页按钮显示俄文的解决办法

    最新的Yandex 20.11.3.179版本浏览器的语言包出现以下错误: 1.zh-CN.pak语言包里面有些俄文没有翻译完,中文"剪切"只翻译了"切".故重 ...

  8. 删除360浏览器新标签页内的热词导航

    在360 浏览器的新标签页中,点击搜索栏经常弹出各种广告文字 为了删除这些内容,只要更改一下360浏览器安装根目录内的 newpages.zip 压缩包里 "new_page.html&qu ...

  9. 在浏览器的标签页显示网站标志图标(或指定图标)的方法

    截个图看下需求: 每个网站都想要自己的logo,实现挺简单的,我分享个地址:点击打开链接   ,里面很详细 下面贴出主要内容: { 对于不同的浏览器,方法是有差别的 1.对于IE或TT浏览器:把需要显 ...

最新文章

  1. git 无法拉取新的远程分支
  2. 程序员跳槽的10个建议
  3. centos6.5 yum安装mysql_CentOS 6.5使用yum安装MySQL快速上手必备
  4. 3 帮助命令、用户管理、压缩
  5. WP7 初始屏幕设置
  6. python嵌套列表操作方法_python中多层嵌套列表的拆分方法
  7. Windows Phone 8 获取与监听网络连接状态
  8. Tensorflow Data Adapter Error: ValueError: Failed to find data adapter that can handle input
  9. python在线diff工具在哪_使用Python创建你自己的diff-tool
  10. pip 下载torch gup版本
  11. 以未来式计算机为题目的作文,未来式科技想象作文
  12. 卷积神经网络完整总结
  13. 关于DFU 烧录更新image
  14. cassandra_在Chaordic上从MySQL过渡到Cassandra
  15. 跨境电商账号矩阵运营方法论
  16. 分析了233部职场剧告诉你:国产职场剧为什么这么烂
  17. java多线程(8):Lamda表达式
  18. IPTV桌面系统建设物料和费用:服务器+软件+电视盒
  19. Bootstrap Method
  20. Oracle——单列函数,多表连接

热门文章

  1. github如何配置ssh
  2. Java Swing中的下拉式菜单(menu)、弹出式菜单(JPopupMenu)、选项卡窗体(JTabbedPane),TextArea右键菜单 组件使用案例
  3. 外汇天眼:开仓、平仓、持仓、锁仓是什么意思?
  4. django创建app的命令
  5. 大一c语言挂科分数烟台大学,知乎烟大 | 在烟大挂科是一种什么体验
  6. DOM2和DOM3——JavaScript高级程序设计第三版第12章知识总结
  7. Censored! :ac自动机 + DP
  8. DeferredShading
  9. C语言:习题11-1 输出月份英文名.2021-07-25
  10. php降序怎写,PHP数组如何按键名实现降序排列