页面间同步状态一般都有哪些方案,分别的应用场景都是哪些
1. 通过storage事件:(同源)
不同tab的js执行环境是不同的,因此变量不会共享,watcher也不会互相影响。
可以利用 storage事件监控localstorge的变化 ,storege事件只能注册在window上
- 只有当存储的值改变时才会触发storage事件,即新值与旧值不同
- 触发写入操作的页面下的storage listener不会被触发
- 即使页面不再同一个浏览器窗口(比如打开两个Chrome浏览器实例),storage也能够触发
- safari隐身模式下无法设置localStorage值
创建两个页面 A和B 分别在不同的Tab打开.
A页面
<!DOCTYPE html>
<html>
<head lang="en">
<title>A</title>
</head>
<body>
<div>我是A页面</div>
<div>
收到来自B页面发送的消息:
<ul id="aMsg"></ul>
</div>
<script>
window.addEventListener('storage', function(e) {
var li = document.createElement('li')
li.innerText = e.newValue
document.getElementById('aMsg').appendChild(li)
})
</script>
</body>
</html>
B页面
<!DOCTYPE html>
<html>
<head lang="en">
<title>B</title>
</head>
<body>
<div>我是B页面</div>
<div>
<button onclick="postMsg()">发送消息</button>
<input id='inp'/>
</div>
<script>
function postMsg() {
localStorage.clear()
localStorage.setItem('foo', document.getElementById('inp').value)
}
</script>
</body>
</html>
B页面发送数据
A页面接收数据
2. 通过BroadcastChannel (同源)
BroadCast Channel可以帮我们创建一个用于广播的通信频道。当所有页面都监听同一频道的消息时,其中某一个页面通过它发送的消息就会被其他所有页面收到。它的API和用法都非常简单。
下面的方式就可以创建一个标识为AlienZHOU
的频道:
A
<!DOCTYPE html>
<html>
<head lang="en">
<title>A</title>
</head>
<body>
<div>我是A页面</div>
<div>
收到来自B页面发送的消息:
<ul id="aMsg"></ul>
</div>
<script>
//A,B页面需要同样的通信key
const bc = new BroadcastChannel('myMsg')
bc.onmessage = function(e) {
const data = e.data
const text = '[receive] ' + data.msg + ' —— tab ' + data.from
console.log(e.data, e.currentTarget.name)
}
</script>
</body>
</html>
B
<!DOCTYPE html>
<html>
<head lang="en">
<title>B</title>
</head>
<body>
<div>我是B页面</div>
<div>
<button onclick="postMsg()">发送消息</button>
<input id="inp" />
</div>
<script>
function postMsg() {
//A,B页面需要同样的通信key
const bc = new BroadcastChannel('myMsg')
bc.postMessage(document.getElementById('inp').value)
}
</script>
</body>
</html>
发送消息:
收到消息:
3. shareWorker (同源)
A页面
<!DOCTYPE html>
<html>
<head lang="en">
<title>A</title>
</head>
<body>
<div>我是A页面</div>
<div>
收到来自B页面发送的消息:
<ul id="aMsg"></ul>
</div>
<script>
// SharedWorker可以被多个window共同使用,但必须保证这些标签页都是同源的
var sharedworker = new SharedWorker('./worker.js')
sharedworker.port.start()
// 接收消息
sharedworker.port.onmessage = msg => {
console.log(msg)
}
</script>
</body>
</html>
B
<!DOCTYPE html>
<html>
<head lang="en">
<title>B</title>
</head>
<body>
<div>我是B页面</div>
<div>
<button onclick="postMsg()">发送消息</button>
<input id="inp" />
</div>
<script>
var sharedworker = new SharedWorker('./worker.js')
function postMsg() {
// 发送消息
sharedworker.port.postMessage(document.getElementById('inp').value)
}
</script>
</body>
</html>
work.js
const ports = []
onconnect = e => {
const port = e.ports[0]
ports.push(port)
port.onmessage = msg => {
ports
.filter(v => v !== port) // 此处为了贴近其他方案的实现,剔除自己
.forEach(p => p.postMessage(msg.data))
}
}
4. postMessage+iframe
postMessage的兼容性较好,可以跨域传递消息,但需要获取到目标窗口引用才行,因此使用有局限性。
A
<!DOCTYPE html>
<html>
<head lang="en">
<title>A</title>
</head>
<body>
<div>我是A页面</div>
<div>
收到来自B页面发送的消息:
<dic id="aMsg"></div>
</div>
<script>
function receiveMessage(e) {
document.getElementById('aMsg').innerHTML = e.data
e.source.postMessage('我是A页面,给你发消息')
console.log('A页面',e)
}
//接收B页面的消息
window.addEventListener('message', receiveMessage, false)
</script>
</body>
</html>
B
<!DOCTYPE html>
<html>
<head lang="en">
<title>B</title>
</head>
<body>
<div>我是B页面</div>
<button id="postBtn">发送</button>
<input id="inp" />
<iframe src="http://127.0.0.1:5500/inde.html" id="aPage" frameborder="0"></iframe>
<script>
postBtn.onclick = function() {
document.getElementById('aPage').contentWindow.postMessage(document.getElementById('inp').value)
}
function receiveMessage(e) {
console.log('B页面', e)
}
// 接收A页面的消息
window.addEventListener('message', receiveMessage, false)
</script>
</body>
</html>