浏览器标签页通信实现打开新窗口播放音乐
浏览器标签页通信实现打开新窗口播放音乐
- 1.项目场景
- 2.模拟实现
- 2.1通过窗口传递数据
- 2.2使用broadcastChannel实现标签页间通信
1.项目场景
我们来看一个项目场景,下面是一个音乐网站。右侧是音乐列表。
点击列表第一首歌的播放按钮,浏览器会新建一个标签页,同时在新标签页展示这首歌的详情。
点击列表第二首歌的播放按钮,原来的标签页会重新展示第二首歌的详情(浏览器不会再新建一个标签页)。并且这个页面是没有进行刷新的。
2.模拟实现
如图,列表有三条数据,我们希望点击播放后会有上述某音乐网站这样子类似的效果。该问题的关键点是在新标签页需要知道主页面中点击的歌曲是哪一首。我们想到的是通过窗口传递数据:
2.1通过窗口传递数据
如下是文件夹结构:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>音乐列表</title>
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div class="music-box">
<div class="music-list">
<div class="music-item">
<span>晴天</span>
<img data-name="晴天" src="./images/play.png" />
</div>
<div class="music-item">
<span>黄昏</span>
<img data-name="黄昏" src="./images/play.png" />
</div>
<div class="music-item">
<span>童话</span>
<img data-name="童话" src="./images/play.png" />
</div>
</div>
</div>
</body>
<script>
const btns = document.querySelectorAll(".music-item img");
for (const btn of btns) {
btn.onclick = function () {
const name = this.dataset.name;
//第二个参数传自定义的名字music,表示打开的窗口目标名字。
// 如果找不到这个标签页名字就会新建一个标签页,取名为music
//如果标签页存在,就会让该页面刷新页面
window.open("./music.html?name=" + name, "music");
};
}
</script>
</html>
musci.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>音乐详情</title>
<link rel="stylesheet" href="./css/music.css" />
</head>
<body>
<div class="music-detail">
<span></span>
</div>
<script>
function play(name) {
const text = document.querySelector(".music-detail span");
text.textContent = name + "正在播放";
}
const params = new URLSearchParams(location.search);
const name = params.get("name");
if (name) {
play(name);
}
</script>
</body>
</html>
如上,看样子需求是实现了,但每次点击播放时候,新标签页就是一次刷新,这明显与现代浏览器格格不入,如果音乐详情页面数据布局很多,会出现卡顿情况。如果能想办法让标签页不重新刷新就好了。那就要使用标签页的通信了。
2.2使用broadcastChannel实现标签页间通信
index.html:
<script>
const btns = document.querySelectorAll(".music-item img");
//不管有多少标签页,只要能满足以下两个条件,他们就可以共用一个频道
//a.标签页之间是同源的 b.频道名字要相同
const channel = new BroadcastChannel("music");
for (const btn of btns) {
btn.onclick = function () {
const name = this.dataset.name;
//打开页签的数目
let n = localStorage.getItem("tabs");
if (!isNaN(n) && n > 0) {
channel.postMessage(name);
} else {
window.open("./music.html?name=" + name, "_blank");
}
};
}
</script>
music.html:
<script>
function play(name) {
const text = document.querySelector(".music-detail span");
text.textContent = name + "正在播放";
}
const params = new URLSearchParams(location.search);
const name = params.get("name");
if (name) {
play(name);
}
const channel = new BroadcastChannel("music");
let n = localStorage.getItem("tabs");
if (isNaN(n)) {
n = 0;
}
n++;
localStorage.setItem("tabs", n);
window.addEventListener("unload", () => {
let n = localStorage.getItem("tabs");
if (isNaN(n)) {
n = 1;
}
n--;
localStorage.setItem("tabs", n);
});
channel.addEventListener("message", (e) => {
play(e.data);
});
</script>
后续我将写一篇文章https://blog.csdn.net/fageaaa/article/details/145659087讲述浏览器标签页的通信方式。