浏览器内多个标签页之间通信,通俗的讲就是浏览器中开了多个窗口,在其中一个窗口做了一些行为等其他窗口不用刷新也能有相关表现。
一、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 init
(npm安装及配置步骤)初始化一个简单的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>