- 完整播放控制 - 播放/暂停、上一首/下一首、循环播放
- 音量控制 - 音量滑块调节、静音/取消静音、悬停显示
- 智能进度条 - 拖拽跳转、点击定位、悬停预览、缓冲显示
- 歌词同步 - 实时滚动高亮、点击歌词跳转、展开/收起控制
- 播放列表 - 多首歌曲切换、歌曲信息展示
- 现代化UI - 毛玻璃效果、渐变背景、阴影层次、圆角设计
- 动画效果 - 专辑封面旋转、彩虹边框流动、脉冲呼吸、按钮悬停
- 响应式布局 - 完美适配桌面端和移动端
- 暗色模式 - 自动跟随系统主题,完美的明暗切换
- 两种模式 - 迷你播放器和完整播放器,流畅切换动画
- Vue 3 + TypeScript - 现代化框架,完整类型安全
- Tailwind CSS 4 - 最新版本的原子化CSS框架
- Vite构建 - 快速的开发和构建体验
- 组合式API - 灵活的状态管理和逻辑复用
- 智能错误处理 - 音频加载失败的友好提示和重试机制
▶️ 播放/暂停 - 一键切换播放状态,流畅的动画过渡- ⏮️ 上一首/下一首 - 快速切换歌曲,支持循环播放
- 🔊 音量控制 - 拖拽式音量滑块,支持静音/取消静音
- ⏱️ 进度控制 - 支持拖拽、点击跳转、悬停预览时间点
- 📝 实时同步 - 歌词随播放进度自动滚动和高亮
- 🎯 交互跳转 - 点击任意歌词行跳转到对应时间
- 📖 展开/收起 - 灵活的歌词面板显示控制
- 🎨 视觉效果 - 当前歌词高亮,非活跃歌词半透明
- 🌈 彩虹边框 - 播放时的流动彩色边框动画
- 💿 封面旋转 - 专辑封面的平滑旋转效果
- ✨ 毛玻璃背景 - 现代化的半透明背景效果
- 🎯 脉冲动画 - 播放时整体的呼吸脉冲效果
- 💫 悬停交互 - 按钮和控件的悬停放大效果
- 🔹 迷你模式 - 紧凑的播放器界面,适合固定在页面角落
- 🔸 完整模式 - 完整的播放器界面,显示所有功能和信息
- 🔄 流畅切换 - 两种模式间的平滑过渡动画
- 📱 自适应布局 - 根据屏幕尺寸自动调整界面元素
- 前端框架: Vue 3 + TypeScript
- 构建工具: Vite 7.0
- 样式框架: Tailwind CSS 4.1
- 图标库: Carbon Icons
- 组合函数: @vueuse/core
- 包管理器: pnpm
- 开发工具: ESLint + Vitest
# 确保安装了 pnpm
npm install -g pnpm
# 克隆项目
git clone https://github.com/Simon-He95/vue-music.git
cd vue-music
# 安装依赖
pnpm install
# 启动开发服务器 (默认端口 3333)
pnpm dev
# 或者指定其他端口
pnpm dev --port 8080
# 构建生产版本
pnpm build
# 预览构建结果
pnpm preview
将您的音频文件放在 public/audio/
目录下:
public/audio/
├── daoxiang.mp3 # 音频文件
├── daoxiang.lrc.ts # 对应的歌词文件
├── kaibuliaokou.mp3 # 音频文件
├── kaibuliaokou.lrc.ts # 对应的歌词文件
└── sample1.mp3 # 更多音频文件...
支持的音频格式: mp3
, wav
, ogg
, m4a
, flac
歌词文件使用TypeScript格式,例如 song.lrc.ts
:
export default [
{ time: 0, words: '第一句歌词' },
{ time: 5.5, words: '第二句歌词' },
{ time: 12, words: '第三句歌词' },
// time: 时间戳(秒),支持小数
// words: 歌词文本
]
在 MusicPlayer.vue
组件中配置您的歌曲列表:
const playlist = ref<Song[]>([
{
id: 1,
title: '稻香',
artist: '周杰伦',
cover: 'https://example.com/cover.jpg',
src: '/audio/daoxiang.mp3',
lyrics: daoxiangLyrics // 从 .lrc.ts 文件导入
},
{
id: 2,
title: '开不了口',
artist: '周杰伦',
cover: 'https://example.com/cover2.jpg',
src: '/audio/kaibuliaokou.mp3',
lyrics: kaibuliaoukouLyrics
}
// 添加更多歌曲...
])
<script setup>
import type { Song } from 'vue3-music-player'
import { MusicPlayer } from 'vue3-music-player'
// 准备播放列表数据
const playlist: Song[] = [
{
id: 1,
title: '歌曲名称',
artist: '艺术家',
cover: '封面图片URL',
src: '/audio/song.mp3',
lyrics: [ // 可选
{ time: 0, words: '歌词内容' }
]
}
]
</script>
<template>
<div class="app">
<MusicPlayer :playlist="playlist" />
</div>
</template>
- 播放/暂停: 点击中央的播放按钮
- 切换歌曲: 使用左右箭头按钮或键盘方向键
- 音量调节:
- 悬停在音量图标上显示音量滑块
- 拖拽滑块或点击任意位置调节音量
- 点击音量图标快速静音/取消静音
- 跳转播放: 点击进度条任意位置直接跳转
- 拖拽控制: 拖拽进度条上的小圆点精确控制
- 悬停预览: 鼠标悬停在进度条上预览时间点
- 展开歌词: 点击歌词按钮展开歌词面板
- 歌词跳转: 点击任意歌词行跳转到对应播放时间
- 自动滚动: 歌词会随播放进度自动滚动和高亮
- 收起歌词: 点击收起按钮或播放器外区域关闭歌词面板
- 迷你模式: 默认的紧凑显示模式
- 完整模式: 点击展开按钮显示完整播放器界面
- 模式切换: 流畅的动画过渡效果
- 彩虹边框 - 播放时的流动彩色边框,呈现波浪式动画
- 专辑旋转 - 封面图片的平滑旋转效果,播放时持续旋转
- 脉冲呼吸 - 整体播放器的轻微缩放脉冲效果
- 按钮悬停 - 所有交互元素的放大和阴影效果
- 模式切换 - 迷你/完整模式间的流畅过渡动画
- 毛玻璃效果 - 半透明背景配合模糊效果
- 渐变色彩 - 多层次的颜色渐变背景
- 阴影层次 - 多重阴影营造立体感
- 圆角设计 - 现代化的圆角矩形界面
- 色彩主题 - 自动适配明暗主题
- 断点适配 - 智能适配不同屏幕尺寸
- 触摸优化 - 移动端的触摸手势支持
- 布局调整 - 小屏幕下的界面元素重新排列
- 字体缩放 - 根据屏幕尺寸自动调整字体大小
播放器会自动跟随系统的明暗主题设置:
- 自动检测 - 基于
prefers-color-scheme
媒体查询 - 动态切换 - 主题变化时的平滑过渡效果
- 颜色适配 - 所有UI元素都完美适配明暗主题
播放器具有完善的错误处理机制:
- 音频加载失败 - 显示友好的错误提示信息
- 网络连接问题 - 自动重试机制和状态反馈
- 格式不支持 - 清晰的格式支持说明
- 封面加载失败 - 自动显示精美的默认封面
- 懒加载 - 音频文件的按需加载
- 缓存策略 - 智能的资源缓存机制
- 防抖处理 - 拖拽和滚动事件的性能优化
- 内存管理 - 及时清理不需要的资源引用
- Vue 3 Composition API - 使用最新的组合式API,逻辑更清晰
- TypeScript 全覆盖 - 完整的类型定义,开发更安全
- Tailwind CSS 4 - 最新版本的原子化CSS框架
- Vite 7.0 - 极速的开发和构建体验
- ESLint 配置 - 统一的代码风格和质量检查
- 按需加载 - 音频资源的懒加载机制
- 事件防抖 - 拖拽和滚动的性能优化
- 内存管理 - 自动清理无用的事件监听器
- 缓存策略 - 智能的资源缓存和复用
- 60fps 动画 - 流畅的CSS3动画效果
- 键盘支持 - 完整的键盘快捷键操作
- 无障碍访问 - 支持屏幕阅读器和键盘导航
- 触摸优化 - 移动端的触摸手势支持
- 渐进增强 - 优雅降级的功能设计
- 多浏览器兼容 - 支持现代浏览器的完整特性
格式 | 支持程度 | 说明 |
---|---|---|
MP3 | ✅ 完全支持 | 最常用的音频格式 |
WAV | ✅ 完全支持 | 无损音频格式 |
OGG | ✅ 完全支持 | 开源音频格式 |
M4A | ✅ 完全支持 | 苹果音频格式 |
FLAC | 取决于浏览器支持 |
浏览器 | 最低版本 | 支持程度 |
---|---|---|
Chrome | 90+ | ✅ 完全支持 |
Firefox | 88+ | ✅ 完全支持 |
Safari | 14+ | ✅ 完全支持 |
Edge | 90+ | ✅ 完全支持 |
移动浏览器 | - | ✅ 完全支持 |
欢迎贡献代码!请遵循以下步骤:
- Fork 项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature
) - 提交更改 (
git commit -m 'Add some AmazingFeature'
) - 推送到分支 (
git push origin feature/AmazingFeature
) - 打开 Pull Request
- 使用 TypeScript 进行类型检查
- 遵循 ESLint 代码规范
- 编写必要的测试用例
- 保持代码注释的完整性
MusicPlayer 组件通过 defineExpose
暴露了丰富的 API,允许父组件程序化地控制播放器:
<script setup lang="ts">
import type { MusicPlayerAPI } from '@/components/exports'
import { ref } from 'vue'
import { MusicPlayer } from '@/components/exports'
const playerRef = ref<MusicPlayerAPI>()
function playMusic() {
playerRef.value?.play()
}
function pauseMusic() {
playerRef.value?.pause()
}
function nextTrack() {
playerRef.value?.next()
}
function showLyrics() {
playerRef.value?.showLyrics()
}
</script>
<template>
<div>
<MusicPlayer ref="playerRef" :playlist="playlist" />
<div class="controls">
<button @click="playMusic">
播放
</button>
<button @click="pauseMusic">
暂停
</button>
<button @click="nextTrack">
下一首
</button>
<button @click="showLyrics">
显示歌词
</button>
</div>
</div>
</template>
play()
- 开始播放pause()
- 暂停播放toggle()
- 切换播放/暂停状态stop()
- 停止播放并重置进度
next()
- 下一首歌曲previous()
- 上一首歌曲skipTo(index: number)
- 跳转到指定索引的歌曲
seekTo(time: number)
- 跳转到指定时间(秒)seekToPercentage(percentage: number)
- 跳转到指定百分比位置
setVolume(volume: number)
- 设置音量(0-1)mute()
- 静音unmute()
- 取消静音toggleMute()
- 切换静音状态
setPlayMode(mode: 'sequence' | 'loop' | 'random')
- 设置播放模式togglePlayMode()
- 循环切换播放模式
expand()
- 展开播放器collapse()
- 收起播放器toggleExpanded()
- 切换展开状态
showLyrics()
- 显示歌词hideLyrics()
- 隐藏歌词toggleLyrics()
- 切换歌词显示状态
setPosition(x: number, y: number)
- 设置播放器位置centerPlayer()
- 将播放器居中显示
getCurrentSong()
- 获取当前歌曲信息getCurrentTime()
- 获取当前播放时间getDuration()
- 获取歌曲总时长getVolume()
- 获取当前音量getProgress()
- 获取播放进度百分比getPlayMode()
- 获取当前播放模式getPosition()
- 获取播放器位置
isPlaying()
- 是否正在播放isExpanded()
- 是否已展开isLoading()
- 是否正在加载hasError()
- 是否有错误isMuted()
- 是否静音isShowingLyrics()
- 是否显示歌词
reload()
- 重新加载当前歌曲skipToNextPlayable()
- 跳过错误歌曲到下一首可播放的
<script setup lang="ts">
import type { MusicPlayerAPI } from '@/components/exports'
import { onMounted, ref } from 'vue'
import { MusicPlayer } from '@/components/exports'
const playerRef = ref<MusicPlayerAPI>()
onMounted(() => {
// 自动播放第一首歌
setTimeout(() => {
playerRef.value?.play()
}, 1000)
// 设置音量为 50%
playerRef.value?.setVolume(0.5)
// 设置随机播放模式
playerRef.value?.setPlayMode('random')
// 将播放器定位到屏幕右下角
playerRef.value?.setPosition(window.innerWidth - 340, window.innerHeight - 84)
})
// 监听键盘快捷键
function handleKeydown(event: KeyboardEvent) {
if (!playerRef.value)
return
switch (event.code) {
case 'Space':
event.preventDefault()
playerRef.value.toggle()
break
case 'ArrowRight':
event.preventDefault()
playerRef.value.next()
break
case 'ArrowLeft':
event.preventDefault()
playerRef.value.previous()
break
case 'KeyL':
event.preventDefault()
playerRef.value.toggleLyrics()
break
}
}
onMounted(() => {
document.addEventListener('keydown', handleKeydown)
})
onUnmounted(() => {
document.removeEventListener('keydown', handleKeydown)
})
</script>