浏览器标签页间通讯
# 1. 应用背景
平常项目开发中,我们经常用到组件见得通讯传参,包括但不限于父子组件,祖孙组件等等。那么在浏览器的页签关系,应该如何进行跨页面传参呢?
接下来以一个简易的播放音乐,来进行示范
# 2. 音乐播放简易代码
<div>
<div class="music-item">
<span class="title">王昭君</span>
<i data-name="王昭君.ogg" class="play-ico"></i>
</div>
<div class="music-item">
<span class="title">玫瑰花的葬礼</span>
<i data-name="玫瑰花的葬礼.ogg" class="play-ico"></i>
</div>
<div class="music-item">
<span class="title">明天过后</span>
<i data-name="明天过后.ogg" class="play-ico"></i>
</div>
</div>
<script>
// 拿到所有的播放按钮
const allPlays = document.querySelectorAll('.music-item i')
// 循环添加事件
for (const btn of allPlays) {
btn.onclick = function (){
// 拿到 data-name 的取值
const name = this.dataset.name
// 打开新的标签页
// 第二个参数时 打开目标, 类似于 a标签的 target
// 因此当标签页存在 music 的时候, 就不会再次创建一个新的便签页, 而是重新刷新页面
window.open(`./music.html?name=${name}`,'music')
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!-- 音乐播放页面 -->
<audio controls></audio>
<script>
const audio = document.querySelector('audio')
function play(name){
// 加载 对应名字的音乐文件
audio.src = `./music/${name}`
audio.play()
}
// 利用 webAPI 拿到地址栏参数
const params = new URLSearchParams(location.search)
const name = params.get('name')
play(name)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
window.open()
虽然可以创建新的标签页,通过第二个参数,来指定目标标签页是否被创建,但是存在一个问题,就是每次都会导致整个页面重新刷新
然后页面是复杂的,显然这种解决方案不太好,因此可以使用 H5 的 API 来进行标签页通讯
# 3. BroadcastChannel API
BroadcastChannel
接口代理了一个命名频道,可以让指定 origin 下的任意 browsing context 来订阅它。
它允许同源的不同浏览器窗口,Tab 页,frame 或者 iframe 下的不同文档之间相互通信
通过触发一个 message 事件,消息可以广播到所有监听了该频道的 BroadcastChannel 对象。
<!-- 发送页 -->
<script>
// 拿到所有的播放按钮
const allPlays = document.querySelectorAll('.music-item i')
// 创建代理频道
const channel = new BroadcastChannel('music')
// 循环添加事件
for (const btn of allPlays) {
btn.onclick = function (){
const name = this.dataset.name;
// 判断是否存在播放页
// 方案一 因为同源状态, 可以在localhost设置一个变量来判断是否存在
// 方案二 同样采用频道通讯,每次打开播放页,想列表页发状态,关闭时更新状态
if(判断是否存在播放页){
// 通过 postMessage 方法进行发送数据
channel.postMessage(name)
}else{
window.open(`./music.html?name=${name}`,'music')
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 接收页 -->
<script>
// 接收数据的页面, 也要创建 频道, 并且频道名字要相同
const channel = new BroadcastChannel('music')
// 通过监听 message 事件, 来获取信息
channel.addEventListener('message',(e)=>{
play(e.data)
})
</script>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
上次更新: 12/26/2023, 8:39:40 AM