vue音乐播放实现
Vue 音乐播放实现
基础播放器组件
创建一个基础的音频播放器组件,使用 HTML5 的 <audio> 元素,结合 Vue 的数据绑定和控制方法。
<template>
<div class="audio-player">
<audio ref="audio" :src="currentSong.url" @timeupdate="updateTime"></audio>
<div class="controls">
<button @click="togglePlay">{{ isPlaying ? '暂停' : '播放' }}</button>
<input type="range" v-model="currentTime" max="100" @input="seek">
<span>{{ formatTime(currentTime) }} / {{ formatTime(duration) }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
currentSong: {
url: 'https://example.com/song.mp3',
title: '示例歌曲'
},
isPlaying: false,
currentTime: 0,
duration: 0
}
},
methods: {
togglePlay() {
const audio = this.$refs.audio
this.isPlaying ? audio.pause() : audio.play()
this.isPlaying = !this.isPlaying
},
updateTime() {
const audio = this.$refs.audio
this.currentTime = (audio.currentTime / audio.duration) * 100
this.duration = audio.duration
},
seek(e) {
const audio = this.$refs.audio
const seekTime = (e.target.value / 100) * audio.duration
audio.currentTime = seekTime
},
formatTime(seconds) {
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins}:${secs < 10 ? '0' : ''}${secs}`
}
}
}
</script>
播放列表管理
实现一个播放列表功能,允许用户切换歌曲。
<template>
<div>
<ul class="playlist">
<li v-for="(song, index) in playlist" :key="index" @click="playSong(index)">
{{ song.title }}
</li>
</ul>
<audio-player :currentSong="currentSong" ref="player"></audio-player>
</div>
</template>
<script>
import AudioPlayer from './AudioPlayer.vue'
export default {
components: { AudioPlayer },
data() {
return {
playlist: [
{ url: 'https://example.com/song1.mp3', title: '歌曲1' },
{ url: 'https://example.com/song2.mp3', title: '歌曲2' }
],
currentSong: {},
currentIndex: 0
}
},
created() {
this.currentSong = this.playlist[0]
},
methods: {
playSong(index) {
this.currentIndex = index
this.currentSong = this.playlist[index]
this.$nextTick(() => {
this.$refs.player.togglePlay()
})
}
}
}
</script>
音频可视化
使用 Web Audio API 实现音频可视化效果。
methods: {
setupVisualizer() {
const audioContext = new (window.AudioContext || window.webkitAudioContext)()
const analyser = audioContext.createAnalyser()
const source = audioContext.createMediaElementSource(this.$refs.audio)
source.connect(analyser)
analyser.connect(audioContext.destination)
analyser.fftSize = 256
const bufferLength = analyser.frequencyBinCount
const dataArray = new Uint8Array(bufferLength)
const canvas = this.$refs.canvas
const ctx = canvas.getContext('2d')
function draw() {
requestAnimationFrame(draw)
analyser.getByteFrequencyData(dataArray)
ctx.fillStyle = 'rgb(0, 0, 0)'
ctx.fillRect(0, 0, canvas.width, canvas.height)
const barWidth = (canvas.width / bufferLength) * 2.5
let x = 0
for(let i = 0; i < bufferLength; i++) {
const barHeight = dataArray[i] / 2
ctx.fillStyle = `rgb(${barHeight + 100}, 50, 50)`
ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight)
x += barWidth + 1
}
}
draw()
}
}
响应式设计
确保播放器在不同设备上都能良好显示。
.audio-player {
max-width: 500px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
border-radius: 8px;
}
.controls {
display: flex;
align-items: center;
gap: 10px;
}
input[type="range"] {
flex-grow: 1;
}
.playlist {
list-style: none;
padding: 0;
}
.playlist li {
padding: 10px;
cursor: pointer;
border-bottom: 1px solid #eee;
}
.playlist li:hover {
background: #f0f0f0;
}
canvas {
width: 100%;
height: 100px;
margin-top: 20px;
}
进阶功能
添加歌词同步功能,需要准备时间戳标记的歌词文件。
methods: {
loadLyrics() {
fetch('lyrics.json')
.then(response => response.json())
.then(data => {
this.lyrics = data
this.startLyricsSync()
})
},
startLyricsSync() {
this.lyricsInterval = setInterval(() => {
const currentTime = this.$refs.audio.currentTime
this.currentLyric = this.lyrics.find(line =>
currentTime >= line.time && currentTime < line.time + line.duration
)?.text || ''
}, 100)
}
}
性能优化
使用懒加载技术,仅在需要时加载音频文件。

methods: {
playSong(index) {
if (!this.playlist[index].loaded) {
this.loadSong(index).then(() => {
this.playLoadedSong(index)
})
} else {
this.playLoadedSong(index)
}
},
loadSong(index) {
return new Promise(resolve => {
const audio = new Audio()
audio.src = this.playlist[index].url
audio.addEventListener('canplaythrough', () => {
this.playlist[index].loaded = true
resolve()
})
})
}
}






