什么是跨标签页通讯
同一浏览器,可以打开多个标签页,跨标签页通讯就是,一个标签页能够发消息给另一标签页。
有哪些实现方案
- 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')// 创建SharedWorkerconst 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')// 创建SharedWorkerconst shared = new SharedWorker('shared.js');btn.onclick = function(){// 向SharedWorker发送消息shared.port.postMessage(content.value);content.value = '';}</script>
</body>
</html>