如何实现浏览器内多个标签页之间的通信

浏览器内多个标签页之间通信,通俗的讲就是浏览器中开了多个窗口,在其中一个窗口做了一些行为等其他窗口不用刷新也能有相关表现。

一、cookie+setInterval方式

要想在多个窗口中通信,通信的内容一定不能放在window对象中,因为window是当前窗口的作用域,里面的内容只属于当前窗口。而cookie是浏览器的本地存储机制,和窗口无关。

将要发送的信息写入cookie:

 var msg = documet.querySelector('#msg');
 if(msg.value.trim() != ""){
 	docment.cookie = "msg=" + msg.value.trim();
 }

在另一个页面读取cookie:

 var recMsg = document.querySelector('#recMsg');
 function getValue(key){
	var cookies = '{"'+document.cookie.replace(/=/g,'":"').replace(/;\s+/g,'", "')+'"}';
    cookies = JSON.parse(cookies);
    return cookies[key];
 }
 setInterval(function(){
    recMsg.innerHTML = getValue("msg1");
 },500);

但是由于仅仅从cookie读取信息不能实时更新,需要手动刷新,因此采用setInterval定时器解决,将读取信息的代码封装成一个函数,在定时器内调用即可

缺点:

1)cookie空间有限,容量4k
2)每次http请求都会把当前域的cookie发送到服务器上,浪费带宽
3)setInterval评率设置过大会影响浏览器性能,过小会影响时效性

优点:每个浏览器都兼容

二、websocket协议

websocket是一种网络通信协议,因为http有缺陷,通信只可以由客户端发起,服务器无法主动向客户端发送消息,但如果这时服务器有连续变化的状态,那么就只能使用轮询(每个一段时间,就发出一个询问)的方式来询问。因为websocket拥有全双工(full-duplex)通信自然可以实现多个标签页之间的通信。
发送方先发送消息到WebSocketServer,然后服务端再实时把消息发给接收方

用法:新建webSocket文件夹,在该目录下打开终端,运行npm initnpm安装及配置步骤)初始化一个简单的node项目(因为需要引入ws包),一直按回车到结束就初始了一个简单的node项目。再安装ws包,依旧在当前目录下的终端运行npm i -save ws,在webSocket目录下新建sever.js、send.html、reveive.html文件
在这里插入图片描述

//server.js
//获得WebSocketServer类型
var WebSocketServer = require('ws').Server;
//创建WebSocketServer对象实例,监听指定端口
var wss = new WebSocketServer({ host: '本机ip地址', port: 8080 }, () => {
    console.log('success');
});
//创建保存所有已连接到服务器的客户端对象的数组
var clients = [];
//为服务器添加connection事件监听,当有客户端连接到服务端时,立刻将客户端对象保存进数组中。
wss.on('connection', function (client) {
    console.log("一个客户端连接到服务器");
    // 如果没有这个client对象,说明是第一次连接,就加入到clients中
    if (clients.indexOf(client) === -1) {
        clients.push(client);
        console.log("有" + clients.length + "个客户端在线");
        //为每个client对象绑定message事件,当某个客户端发来消息时,自动触发
        client.on('message', function (msg) {
            console.log("收到消息:" + msg);
            //遍历clients数组中每个其他客户端对象,并发送消息给其他客户端
            for (var c of clients) {
                if (c != client) {
                    c.send(msg);
                }
            }
        });
    }
});
<!-- send.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body style="text-align: right">
    <input id="msg" type="text">
    <button id="send">发送</button>
    <script>
        //建立到服务端webSocket连接
        var ws = new WebSocket("ws://本机ip地址:8080");
        send.onclick = function () {
            if (msg.value.trim() !== "") {
                // 将消息发到服务器
                ws.send(msg.value.trim());
            }
        }
    </script>
</body>

</html>
<!-- receive.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>收到消息: <span id="recMsg"></span></h1>
    <script>
        var recMsg = document.querySelector('#recMsg');
        // 新建FileReader实例
        var reader = new FileReader();
        //建立到服务端webSocket连接
        var ws = new WebSocket("ws://192.168.56.1:8080");
        //当连接被打开时,注册接收消息的处理函数
        ws.onopen = function (event) {
            //当有消息发过来时,就将消息放到显示元素上
            ws.onmessage = function (event) {
                console.log(event.data);
                // event.data是Blob类型,需要转换成字符串输出
                reader.readAsText(event.data);
                reader.onload = function (e) {
                    recMsg.innerHTML = reader.result;
                }
            }
        }
    </script>
</body>

</html>

缺点:需要服务端的支持才能完成任务,如果socket数据量比较大的话,会严重消耗服务器的资源;必须要在服务端项目中写服务端监听程序才能支持。

优点:使用简单,功能灵活,强大,如果部署了WebSocket服务器,可以实现很多实时的功能。

三、localstorage

localStorage比cookie好在它在setItem存东西时会自动触发整个浏览器的storage事件,除了当前页面之外,所有打开的标签窗口都会受影响。

<!-- send.html -->
<body style="text-align: right">
  <input id="msg1" type="text"> 
  <input id="msg2" type="text"> 
  <button id="send">发送</button>
  <script>
    send.onclick = function(){
      if(msg1.value.trim()!=="" && msg2.value.trim()!==""){
        localStorage.setItem("msg1",msg1.value.trim());
        localStorage.setItem("msg2",msg2.value.trim());
      }
    }
  </script>
</body>
<!-- receive.html -->
<body>
  <h1>收到消息:<span id="recMsg"></span></h1>
  <script>
    function load(){
      recMsg.innerHTML = localStorage.getItem("msg1");
    }
    load();
    // 任何页面修改了localStorage的值,都会自动触发其他页面中的storage事件
    // 只要storage一变化我们读取localStorage中对应的值显示到页面上
    window.addEventListener("storage",function(){
      load();
    });
  </script>
</body>

缺点:localStorage是h5属性,高版本浏览器才支持,而且不同浏览器的localStorage大小限制不统一;localStorage只能监听非己页面的数据变化

优点:解决了cookie容量小和时效性问题

四、html5浏览器新特性——SharedWorker

  • WebWorker的升级版,webworker只能在一个窗口内使用,而SharedWorker可以在多个窗口之间通信
  • SharedWorker也是纯客户端的,没有服务端参与
  • SharedWorker在客户端有一个自己维护的对象worker.js,消息存储在worker.js的data中
  • SharedWorker不如localStorage的是接收消息不是自动的,也要用定时器实时从worker.js中获取消息

(worker.js文件暂时有问题待解决)

 // worker.js文件
//在所有SharedWorker共享的worker.js中,保存一个data变量,用于存储多个worker共享的数据
let data = '';
//必须提供一个名为onconnect的事件处理函数
//每当一个页面中new SharedWorker("worker.js")时,就会为新创建的worker绑定onconnect事件处理函数
onconnect = function (e) {
    //获得当前连接上来的客户端对象
    var client = e.ports[0];
    // client.postMessage(data);
    //当当前对象收到消息时
    client.onmessage = function (e) {

        //如果消息内容为空,说明该客户端想获取共享的数据data
        if (e.data === "") {
            //就给当前客户端发送data数据
            client.postMessage(data);
        } else {//否则如果消息内容不为空,说明该客户端想要提供新的消息保存在共享的data中,供别人获取
            data = e.data;
        }
    }
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<!-- send.html文件 -->

<body>
    <input type="text" id="msg"><button id="send">发送</button>
    <script>
        var msg = document.querySelector('#msg');
        var worker = new SharedWorker("./worker.js");
        worker.port.start();
        send.onclick = function () {
            if (msg.value.trim() !== "") {
                console.log(msg.value.trim());
                worker.port.postMessage(msg.value.trim());
            }
        }
    </script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<!-- receive.html文件 -->

<body>
    <h1>收到消息:<span id="recMsg"></span></h1>
    <script>
        var recMsg = document.querySelector('#recMsg');
        var worker = new SharedWorker("./worker.js");
        //3. 当worker.js中给当前客户端返回了data,会触发当前客户端的message事件。data的值,自动保存进事件对象e的data属性中
        worker.port.addEventListener("message", function (e) {
            recMsg.innerHTML = e.data;
        })
        worker.port.start();
        //1. 接收端反复向共享的worker.js对象中发送空消息,意为想获取data的值
        setInterval(function () {
            console.log("请求接收信息");
            worker.port.postMessage("");
            //2. 只要发送消息,就触发worker.js中的onmessage,onmessage判断是空消息内容,说明客户端想获得data。于是就用postMessage()方法,将data返回给当前客户端
        }, 500);
    </script>
</body>

</html>
  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值