什么是跨标签页通讯
同一浏览器,可以打开多个标签页,跨标签页通讯就是,一个标签页能够发消息给另一标签页。
有哪些实现方案
- localStorage (window.onstorage事件监听)
- BroadcastChannel(广播)
- ServiceWorker (代理服务线程)
- SharedWorker + 轮询
- indexedDB + 轮询
- cookie + 轮询
- window.open + window.postMessage()
- WebSocket + 后端服务
方案一:localStorage
基于storage
事件
页面一(localStorage1.html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>localStorage1</title>
</head>
<body>
<h1>localStorage1</h1>
<ul id="ul"></ul>
<script>
/** 更新视图*/
function changeView(){
const ul = document.getElementById('ul');
ul.innerHTML = '';
for(let i = 0; i < localStorage.length; i++){
const key = localStorage.key(i);
const value = localStorage.getItem(key);
const li = document.createElement('li');
li.textContent = `${key}: ${value}`;
ul.appendChild(li);
}
}
/** 数据更新-更新视图*/
function changeData(key,value){
localStorage.setItem(key,value);
changeView();
}
/** 更新localStorage中数据 */
changeData('name','张三')
changeData('age','18')
</script>
</body>
</html>
页面二(localStorage2.html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>localStorage1</title>
</head>
<body>
<h1>localStorage2</h1>
<ul id="ul"></ul>
<script>
function changeView(){
const ul = document.getElementById('ul');
ul.innerHTML = '';
for(let i = 0; i < localStorage.length; i++){
const key = localStorage.key(i);
const value = localStorage.getItem(key);
const li = document.createElement('li');
li.textContent = `${key}: ${value}`;
ul.appendChild(li);
}
}
changeView();
//当localStorage发生变化时,会触发storage事件
window.addEventListener('storage',changeView)
</script>
</body>
</html>
方案二:BroadcastChannel
BroadcastChannel可以创建一个用于广播的通信频道,当所有页面都监听同一频道的消息时,其中某一个页面通过它发送的消息就会被其他页面接收到,前提是同源页面。
页面1(channel1.html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>BroadcastChannel1-Tom</h1>
<p>接收消息:</p>
<p id="message" style="white-space: pre;"></p>
<input type="text" name="message" id="messageInput">
<button onclick="postMessage()">发送消息</button>
<script>
const messageElement = document.getElementById('message');
const messageInput = document.getElementById('messageInput');
const bc = new BroadcastChannel('channel');
bc.onmessage = function(e) {
console.log('收到消息:', e.data);
messageElement.textContent += '\n'+e.data;
}
function postMessage() {
console.log('发送消息');
const message = messageInput.value;
bc.postMessage(message);
messageInput.value = '';
}
</script>
</body>
</html>
页面2(channel1.html):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>BroadcastChannel2-Jerry</h1>
<p>接收消息:</p>
<p id="message" style="white-space: pre;"></p>
<input type="text" name="message" id="messageInput">
<button onclick="postMessage()">发送消息</button>
<script>
const messageElement = document.getElementById('message');
const messageInput = document.getElementById('messageInput');
const bc = new BroadcastChannel('channel');
bc.onmessage = function(e) {
console.log('收到消息:', e.data);
messageElement.textContent += '\n'+e.data;
}
function postMessage() {
console.log('发送消息');
const message = messageInput.value;
bc.postMessage(message);
messageInput.value = '';
}
</script>
</body>
</html>
方案三:ServiceWorker
Service worker 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。
sw.js文件-代理服务器
// 消息会先到达这里,然后发送到其他客户端
self.addEventListener('message', async (event)=> {
// 首先获取所有注册了serviceWorker的客户端
self.clients.matchAll().then((clients)=>{
// 遍历所有客户端
clients.forEach((client)=>{
// 向每个客户端发送消息
client.postMessage(event.data);
})
})
});
service1.html文件-客户端1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>service1</h1>
<input type="text" id="content">
<button id="bt">发送</button>
<script>
/**注册serviceWorker*/
navigator.serviceWorker.register('sw.js').then(function(registration){
console.log('service worker 注册成功');
})
const bt = document.getElementById('bt');
bt.addEventListener('click',function(){
const message = document.getElementById('content').value;
// controller控制器发送消息
navigator.serviceWorker.controller.postMessage(message);
})
</script>
</body>
</html>
service2.html文件-客户端2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>service1</h1>
<script>
/**注册同一serviceWorker*/
navigator.serviceWorker.register('sw.js').then(function(registration){
console.log('service worker 注册成功');
})
//监听onmessage事件
navigator.serviceWorker.onmessage = function(event){
console.log('收到消息',event.data);
}
</script>
</body>
</html>
方案四:SharedWorker + 轮询
SharedWorker
是Worker
的一种,它允许你在多个页面之间共享一个Worker
。
shared.js(worker)
let data = "";//存储用户发送的信息
onconnect = (event) => {
const port = event.ports[0];//获取客户端端口
port.onmessage = (event) => {
if (event.data==='get') {
port.postMessage(data);//向客户端发送消息
}else{
data = event.data;//将用户发送的信息存储到data变量中
}
}
}
shared1.html(页面一)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>shared1</h1>
<input type="text" id="content">
<button id="btn">发送</button>
<script>
const btn = document.getElementById('btn');
const content = document.getElementById('content');
const message = document.getElementById('message')
// 创建SharedWorker
const shared = new SharedWorker('shared.js');
btn.onclick = function(){
// 向SharedWorker发送消息
shared.port.postMessage(content.value);
content.value = '';
}
</script>
</body>
</html>
shared2.html(页面二)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>shared1</h1>
<input type="text" id="content">
<button id="btn">发送</button>
<script>
const btn = document.getElementById('btn');
const content = document.getElementById('content');
const message = document.getElementById('message')
// 创建SharedWorker
const shared = new SharedWorker('shared.js');
btn.onclick = function(){
// 向SharedWorker发送消息
shared.port.postMessage(content.value);
content.value = '';
}
</script>
</body>
</html>