音乐播放器-2
音乐播放器-2
目录
[toc]
已下架
危险
因次功能特别影响首页加载,所以下架次功能。(且音乐播放器功能之前已经实现了的) --2025年4月21日
背景
给你的 vitepress 添加音乐播放器,让你的网站更加有活力。
环境
2025.4.19(已解决)
警告
次配置适用于Teek@1.0.2-2025.4.10
版本(其它版本可自行测试)。
提示
自己开源的 《vitepress-theme-teek-one-public》网站模板。
此模板是在《Young Kbt blog》大佬开源项目《vitepress-theme-teek 》基础上修改为自己的风格而成,感谢大佬开发得主题,大佬威武。❤️❤️
版权
提示
本文是在 博主程序员皮蛋鸽鸽 💻 网站:极客兔 - 笔记站》 看到的 nav 导航栏音乐播放器。在基础上增加了自己实践过程的一些细节,转载无需和我联系,但请注明文章来源。如果侵权之处,请联系博主进行删除,谢谢~
1、安装依赖
警告
基于作者的 vue 组件用了 element-plus 组件提示,所以需要安装 element-plus 组件,不需要可以跳过。
pnpm install element-plus
npm install element-plus --save
yarn add element-plus
2、新建组件
- 在
docs\.vitepress\theme\components\
创建如下文件
详细信息
<script setup lang="ts">
// import '../../lib/iconfont/iconfont'; // vitepress 基于 nodejs 的项目,无法引入需要window对象的模块
import { onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import 'element-plus/dist/index.css'
import PauseMusicController from './PauseMusicController.vue'
import PlayingMusicController from './PlayingMusicController.vue'
/**
*
* 音乐播放器
*/
const musics = [
'成都-赵雷.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>
<script setup lang="ts">
// import '../../lib/iconfont/iconfont'; // vitepress 基于 nodejs 的项目,无法引入需要window对象的模块
import { onMounted, ref } from 'vue'
import { ElMessage } from 'element-plus'
import 'element-plus/dist/index.css'
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>
// 播放时图标
<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>
3、注册组件
- 在
docs\.vitepress\theme\components\TeekLayoutProvider.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>
4、提供音乐源文件
- 在
docs\public\music
目录下放置音乐文件
- 修改
docs\.vitepress\theme\components\MusicPlayer.vue
文件里音乐源文件名称(修改为你自己的音乐名称)
5、验证
运行项目,验证效果:
结束。
关于我
我的博客主旨:
- 排版美观,语言精炼;
- 文档即手册,步骤明细,拒绝埋坑,提供源码;
- 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
🍀 个人网站
🍀 微信二维码
x2675263825 (舍得), qq:2675263825。
🍀 微信公众号
《云原生架构师实战》
🍀 csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421
🍀 知乎
https://www.zhihu.com/people/foryouone
最后
如果你还有疑惑,可以去我的网站查看更多内容或者联系我帮忙查看。
如果你有更好的方式,评论区留言告诉我。谢谢!
好了,本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!