音乐播放器
简介
给你的 vitepress 添加音乐播放器,让你的网站更加有活力。
版权
版权声明
本文是在 博主程序员皮蛋鸽鸽 💻 网站:极客兔 - 笔记站》 看到的 nav 导航栏音乐播放器。在基础上增加了自己实践过程的一些细节,转载无需和我联系,但请注明文章来源。如果侵权之处,请联系博主进行删除,谢谢~
安装依赖
注意
基于作者的 vue 组件用了 element-plus 组件提示,所以需要安装 element-plus 组件,不需要可以跳过。
sh
pnpm install element-plus
sh
npm install element-plus --save
sh
yarn add element-plus
新建组件
- 在
docs\.vitepress\theme\components\
配置以下代码
点我查看
vue
<script setup lang="ts">
// import '../../lib/iconfont/iconfont'; // vitepress 基于 nodejs 的项目,无法引入需要window对象的模块
import { onMounted, ref } from "vue";
import { ElMessage } from "element-plus";
import PauseMusicController from "./PauseMusicController.vue";
import PlayingMusicController from "./PlayingMusicController.vue";
/**
*
* 音乐播放器
*/
const musics = [
"周杰伦-搁浅.mp3",
"林俊杰-不潮不用花钱.mp3",
"林俊杰-可惜没如果.mp3",
"林俊杰-美人鱼.mp3",
"林俊杰-修炼爱情.mp3",
"周杰伦-安静.mp3",
"周杰伦-不能说的秘密.mp3",
"周杰伦-彩虹.mp3",
"周杰伦-断了的弦.mp3",
"周杰伦-搁浅.mp3",
"周杰伦-轨迹.mp3",
"周杰伦-回到过去.mp3",
"周杰伦-借口.mp3",
"周杰伦-晴天.mp3",
"周杰伦-退后.mp3",
];
// 当前音乐
const currentMusic = ref("/music/周杰伦-搁浅.mp3");
// 播放器元素
const audio = ref<HTMLAudioElement | null>();
// 是否播放音乐: 默认: false
const isPlayed = ref(false);
// 播放音乐的随机数字
let random = ref(0);
// 开一个定时器,什么时候需要销毁播放器可以直接清除该查询定时器
let music_palyer_timer = ref<ReturnType<typeof setInterval> | null>();
const playMusic = () => {
/**
* 浏览器为什么不能直接播放音乐参考博客:
* https://blog.csdn.net/s18813688772/article/details/121103802
*/
isPlayed.value = !isPlayed.value;
const musicName =
currentMusic.value
.split("/")
.pop()
?.replace(/\.mp3$/, "") ?? "未知歌曲";
ElMessage({
message: isPlayed.value ? `正在播放: ${musicName}` : `已暂停: ${musicName}`,
type: isPlayed.value ? "success" : "warning",
duration: 2000,
});
console.log("播放状态: ", isPlayed.value ? "播放" : "不播放");
if (isPlayed.value) {
// 如果是播放状态,则播放音乐
audio.value?.play();
} else {
// 如果是暂停状态,则暂停音乐
audio.value?.pause();
const handleLoadError = () => {
ElMessage.error("音乐加载失败,请重试");
};
}
};
const generateRandom = () => {
/**
* 生成一个与上次的数字不一样的数字
*/
let tmp: number = Math.floor(Math.random() * musics.length);
while (tmp === random.value) {
tmp = Math.floor(Math.random() * musics.length);
}
return tmp;
};
onMounted(() => {
// 挂在完成后给一个随机音乐
random.value = generateRandom();
console.log(
`%c第${random.value + 1}首音乐.`,
"color: green; font-weight: bolder;"
);
currentMusic.value = `/music/${musics[random.value]}`;
// 提示用户可以播放音乐
/* setTimeout(() => {
confirm('点击右侧🎵可以播放音乐哦~');
}, 100); */
// 组件挂在完成即开启定时器监听音乐是否播放完成的状态
music_palyer_timer.value = setInterval(function () {
// 如果音频播放器获取到了,就监听是否结束的事件
if (audio.value?.ended) {
console.log("%c音乐结束, 下一曲~", "color: oranger; font-weight: bold;");
// 以播放结束的标志判断
random.value = generateRandom();
console.log(
`%c第${random.value}首音乐.`,
"color: green; font-weight: bolder;"
);
currentMusic.value = `/music/${musics[random.value]}`;
/*audio.value.onended = function () {
// 以播放结束的事件监听形式控制
let random: number = Math.floor(Math.random() * musics.length);
currentMusic.value = `/music/${musics[random]}`;
console.log('音乐结束, 下一曲~');
}*/
}
}, 1000);
});
/**
* 播放定时器的清除看情况 ...
* Todo...
*/
</script>
<template>
<div class="playMusic-wrapper">
<button class="playMusic" @click="playMusic">
<PlayingMusicController v-if="isPlayed" />
<PauseMusicController v-else />
<!-- <svg class="icon" aria-hidden="true">
<use :xlink:href="`#icon-${isPlayed ? 'music' : 'play2'}`"></use>
</svg> -->
</button>
<audio
ref="audio"
preload="auto"
:autoplay="isPlayed"
:src="currentMusic"
style="display: none"
controls
></audio>
</div>
</template>
<style scoped lang="scss">
$PlayControler-width: 20px;
$PlayControler-height: 20px;
.playMusic-wrapper {
display: flex;
justify-content: center;
align-items: center;
width: 36px;
// width: 400px; // 测试
height: 36px;
margin: 0 5px;
.playMusic {
width: $PlayControler-width;
height: $PlayControler-width;
border-radius: 20%;
font-size: 1.3rem;
line-height: 1.3rem;
svg {
margin: 0;
padding: 0;
width: $PlayControler-width;
height: $PlayControler-width;
}
}
}
</style>
vue
// 暂停时图标
<template>
<svg
t="1744867867712"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="7482"
width="256"
height="256"
>
<path
d="M934.4 53.333333c-29.866667-23.466667-68.266667-32-104.533333-23.466666L334.933333 145.066667c-55.466667 12.8-96 61.866667-96 119.466666v443.733334c-14.933333-6.4-32-8.533333-49.066666-8.533334-81.066667 0-147.2 66.133333-147.2 147.2s66.133333 147.2 147.2 147.2c81.066667 0 147.2-66.133333 147.2-147.2V492.8l544-125.866667v341.333334c-14.933333-6.4-32-8.533333-49.066667-8.533334-81.066667 0-147.2 66.133333-147.2 147.2 0 81.066667 66.133333 147.2 147.2 147.2 78.933333 0 142.933333-59.733333 147.2-136.533333 0-4.266667 2.133333-6.4 2.133333-10.666667V151.466667c0-38.4-17.066667-74.666667-46.933333-98.133334zM339.2 390.4v-125.866667c0-10.666667 8.533333-21.333333 19.2-23.466666L851.2 128c10.666667-2.133333 17.066667 2.133333 21.333333 4.266667 4.266667 2.133333 8.533333 8.533333 8.533334 19.2v115.2l-541.866667 123.733333z"
fill="#80B8F8"
p-id="7483"
data-spm-anchor-id="a313x.search_index.0.i37.3afb3a81G2wgGd"
class="selected"
></path>
</svg>
</template>
vue
// 播放时图标
<template>
<svg
t="1706712309791"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1184"
width="200"
height="200"
>
<path
d="M983.38 306.44l-442.628 81.458a17.454 17.454 0 0 0-14.302 17.162v375.822c-31.38-18.59-72.608-24.724-113.914-13.666-74.146 19.85-120.418 87.528-103.352 151.164s91.006 99.13 165.152 79.28c65.884-17.638 109.718-73.042 106.704-129.814h0.188V469.482l367.992-67.74v289.742c-31.38-18.59-72.61-24.724-113.914-13.666-74.146 19.85-120.418 87.528-103.352 151.164 17.066 63.636 91.006 99.13 165.152 79.28 64.794-17.348 108.296-71.218 106.852-126.998H1004l0.008-457.66c0.002-10.906-9.896-19.14-20.628-17.164z"
fill="#707AFA"
p-id="1185"
></path>
<path
d="M474.336 977.676c-74.146 19.85-148.086-15.644-165.152-79.28a103.588 103.588 0 0 1-3.038-16.91c-1.166 12.202-0.254 24.62 3.038 36.894 17.066 63.636 91.006 99.13 165.152 79.28 65.884-17.638 109.718-73.042 106.704-129.814h0.188v-19.984h-0.188c3.014 56.774-40.82 112.176-106.704 129.814zM1004 761.28h-0.042c1.444 55.78-42.058 109.652-106.852 126.998-74.146 19.85-148.086-15.644-165.152-79.28a103.588 103.588 0 0 1-3.038-16.91c-1.166 12.202-0.254 24.62 3.038 36.894 17.066 63.636 91.006 99.13 165.152 79.28 64.794-17.348 108.296-71.218 106.852-126.998H1004l0.008-457.66v-0.006L1004 761.28z"
fill="#6770E6"
p-id="1186"
></path>
<path
d="M487.55 167.318c-30.86-99.616-129.14-131.888-191.96-142.34-15.806-2.62-31.02-3.864-41.386-4.454a12.668 12.668 0 0 0-13.394 12.65v378.478c-31.38-18.59-72.61-24.726-113.916-13.668-74.146 19.85-120.418 87.528-103.352 151.164 17.066 63.636 91.006 99.13 165.152 79.28 65.884-17.638 109.716-73.042 106.704-129.814h0.192V150.392c35.96 2.658 84.72 19.644 130.94 79.312 67.62 87.246 154.7 51.036 154.7 51.036-39.7 0.002-75.24-53.872-93.68-113.422z"
fill="#FF8354"
p-id="1187"
></path>
<path
d="M188.692 607.944c-74.146 19.85-148.086-15.644-165.152-79.28a103.55 103.55 0 0 1-3.008-16.66c-1.204 12.282-0.306 24.79 3.008 37.146 17.066 63.636 91.006 99.13 165.152 79.28 65.884-17.638 109.716-73.042 106.704-129.814h0.192v-20.486h-0.192c3.014 56.774-40.82 112.176-106.704 129.814z"
fill="#E0734A"
p-id="1188"
></path>
<path
d="M126.894 437.954c41.306-11.058 82.536-4.924 113.916 13.668v-39.966c-31.38-18.59-72.61-24.726-113.916-13.668-71.43 19.122-116.964 82.634-104.95 144.156 9.03-47.094 49.064-89.228 104.95-104.19z"
fill="#FFAC8C"
p-id="1189"
></path>
<path
d="M540.752 427.864l442.628-81.456c10.728-1.974 20.62 6.252 20.628 17.148v-39.952c0-10.904-9.896-19.138-20.628-17.162l-442.628 81.456a17.456 17.456 0 0 0-14.302 17.162v39.966a17.454 17.454 0 0 1 14.302-17.162zM835.308 717.784c41.306-11.058 82.534-4.924 113.914 13.666v-39.966c-31.38-18.59-72.61-24.724-113.914-13.666-71.43 19.124-116.964 82.634-104.95 144.156 9.03-47.094 49.064-89.228 104.95-104.19zM412.536 807.182c41.304-11.058 82.532-4.924 113.914 13.666v-39.966c-31.38-18.59-72.608-24.724-113.914-13.666-71.43 19.124-116.964 82.634-104.948 144.156 9.03-47.092 49.064-89.228 104.948-104.19z"
fill="#8F95E6"
p-id="1190"
></path>
<path
d="M244.204 54.496c10.366 0.59 25.582 1.834 41.386 4.454 62.82 10.452 161.1 42.724 191.96 142.34 10.292 33.238 25.916 64.698 44.612 86.018 33.838 3.914 59.066-6.566 59.066-6.566-39.7 0-75.24-53.874-93.68-113.424-30.86-99.616-129.14-131.888-191.96-142.34-15.806-2.618-31.02-3.864-41.386-4.454a12.668 12.668 0 0 0-13.394 12.65v21.598a12.806 12.806 0 0 1 3.396-0.276z"
fill="#FFAC8C"
p-id="1191"
></path>
<path
d="M865.658 118.83c-9.74 0-17.636-7.89-17.636-17.62 0-9.378-7.082-17.566-16.448-18.172-10.264-0.664-18.796 7.456-18.796 17.568v0.604c0 9.732-7.896 17.62-17.636 17.62-9.386 0-17.58 7.076-18.186 16.434-0.664 10.254 7.462 18.78 17.582 18.78h0.604c9.74 0 17.636 7.89 17.636 17.62 0 9.378 7.082 17.566 16.448 18.172 10.264 0.664 18.796-7.456 18.796-17.568v-0.604c0-9.732 7.896-17.62 17.636-17.62h0.604c10.12 0 18.248-8.524 17.584-18.78-0.608-9.358-8.804-16.434-18.188-16.434zM188.01 811.662c-13.588 0-24.602-11.006-24.602-24.582 0-13.082-9.88-24.504-22.946-25.35-14.318-0.926-26.22 10.402-26.22 24.508v0.842c0 13.576-11.014 24.582-24.602 24.582-13.092 0-24.524 9.872-25.37 22.926-0.928 14.306 10.41 26.198 24.528 26.198h0.844c13.588 0 24.602 11.006 24.602 24.582 0 13.082 9.88 24.504 22.946 25.35 14.318 0.926 26.22-10.402 26.22-24.508v-0.842c0-13.576 11.014-24.582 24.602-24.582h0.844c14.118 0 25.456-11.892 24.53-26.198-0.85-13.054-12.282-22.926-25.376-22.926z"
fill="#69EBFC"
p-id="1192"
></path>
</svg>
</template>
注册组件
- 在
docs\.vitepress\theme\components\TeekLayoutProvider.vue
中注册组件
vue
<script setup lang="ts" name="TeekLayoutProvider">
import MusicPlayer from "./MusicPlayer.vue"; // 引入音乐播放器组件
</script>
<template>
<Teek.Layout>
<template #nav-bar-content-after>
<div :class="ns.b('appearance')">...</div>
<!-- 音乐播放器组件 -->
<MusicPlayer />
</template>
</Teek.Layout>
</template>
配置音乐
- 在
docs\public\music
目录下放置音乐文件
md
docs
├── public
│ ├── music
│ │ ├── 周杰伦-搁浅.mp3
│ │ ├── 林俊杰-不潮不用花钱.mp3
│ │ └── 林俊杰-可惜没如果.mp3