跨页面通信
跨域页面分为两种:
- 不同标签页间通信
iframe
的页面通信
1. localStorage + storage 事件实现
因为 storage
事件是可以跨标签页的,所以我们可以通过在页面中监听 storage
事件进行数据传递。
假设我们需要从 A
页面发送数据给 B
页面
页面 A:
JS
// A 页面有个 btn 按钮,我们写入数据到存储中
btn.addEventListener("click", () => {
localStorage.setItem("message", "hello world")
})
// A 页面有个 btn 按钮,我们写入数据到存储中
btn.addEventListener("click", () => {
localStorage.setItem("message", "hello world")
})
1
2
3
4
2
3
4
页面 B:
JS
// B 页面监听存储的变化,获取到对应的值
window.addEventListener("storage", (e) => {
// e 是一个 StorageEvent 事件对象,内部有多种属性,主要用到的属性如下
// newValue 改变后的值
// oldValue 原有的值
// key 存储字段的属性 key,这里是对应上面的 message
const { newValue, oldValue, key } = e
})
// B 页面监听存储的变化,获取到对应的值
window.addEventListener("storage", (e) => {
// e 是一个 StorageEvent 事件对象,内部有多种属性,主要用到的属性如下
// newValue 改变后的值
// oldValue 原有的值
// key 存储字段的属性 key,这里是对应上面的 message
const { newValue, oldValue, key } = e
})
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
注意:
- 页面需要同源,
sessionStorage
在不同标签页中是无法触发storage
事件的,因为他们不共享,只有在iframe
页面中才行。 - 如果只有一个页面,也无法触发
storage
事件,必须是1个以上标签页中才能进行监听(虽然一个页面时直接修改浏览器的storage
值会触发,但是使用代码是无法触发的)
2. 使用 websocket
websocket
协议是一个全双工通信的协议,客户端和服务端可以互相通信。
页面 A:
JS
// 创建 websocket 连接
var ws = new WebSocket('ws://localhost:3000/');
// A 页面有个 btn 按钮,向服务端发送消息
btn.addEventListener("click", () => {
ws.send('hello world')
})
// 创建 websocket 连接
var ws = new WebSocket('ws://localhost:3000/');
// A 页面有个 btn 按钮,向服务端发送消息
btn.addEventListener("click", () => {
ws.send('hello world')
})
1
2
3
4
5
6
7
2
3
4
5
6
7
页面 B:
JS
var ws = new WebSocket('ws://localhost:3000/');
// 接受服务器端转发过来的消息
ws.onmessage = function (e) {
console.log(e.data) // hello world
}
var ws = new WebSocket('ws://localhost:3000/');
// 接受服务器端转发过来的消息
ws.onmessage = function (e) {
console.log(e.data) // hello world
}
1
2
3
4
5
6
2
3
4
5
6
没有同源共享策略限制,可跨域共享
3. sharedWorker
sharedWorker
是 webWorker
的一种,其可在同源页面中共享;如果多个页面的 url
一致,则只会创建一个sharedWorker
,多个页面共享这个 sharedWorker
。
worker.js
JS
const set = new Set() // 创建一个不重复的变量
onconnect = event => {
const port = event.ports[0]
set.add(port)
// 接收信息
port.onmessage = e => {
// 广播信息
set.forEach(p => {
p.postMessage(e.data)
})
}
// 发送信息
port.postMessage("worker 广播信息")
}
const set = new Set() // 创建一个不重复的变量
onconnect = event => {
const port = event.ports[0]
set.add(port)
// 接收信息
port.onmessage = e => {
// 广播信息
set.forEach(p => {
p.postMessage(e.data)
})
}
// 发送信息
port.postMessage("worker 广播信息")
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
页面 A:
JS
const worker = new SharedWorker('./worker.js')
btn.addEventListener("click", () => {
// 发送消息
worker.port.postMessage('hello world')
})
const worker = new SharedWorker('./worker.js')
btn.addEventListener("click", () => {
// 发送消息
worker.port.postMessage('hello world')
})
1
2
3
4
5
6
2
3
4
5
6
页面 B:
js
const worker = new SharedWorker('./worker.js')
// 接收消息
worker.port.onmessage = e => {
console.info(e.data) // hello world
}
const worker = new SharedWorker('./worker.js')
// 接收消息
worker.port.onmessage = e => {
console.info(e.data) // hello world
}
1
2
3
4
5
2
3
4
5
4. cookie + setInterval
利用 cookie
的同源共享特点,使用定时器轮询查看内容是否变更。
页面 A:
JS
// 使用定时器每秒获取一次 cookie 信息,根据业务需求对比内容是否变更
setInterval(() => {
console.log("cookie", document.cookie)
}, 1000);
// 使用定时器每秒获取一次 cookie 信息,根据业务需求对比内容是否变更
setInterval(() => {
console.log("cookie", document.cookie)
}, 1000);
1
2
3
4
2
3
4
页面 B:
JS
btn.addEventListener("click", () => {
document.cookie = 'hello world'
})
btn.addEventListener("click", () => {
document.cookie = 'hello world'
})
1
2
3
2
3
总结
实现 | 优点 | 缺点 |
---|---|---|
localStorage | 简单且易于理解 | 不能跨域 |
websocket | 可跨域,内容无限制 | 需要服务端配合 |
sharedWorker | 性能好,原生支持 | 不能跨域,兼容性一般 |
cookie + setInterval | - | 存储大小限制,且会随请求携带 |