在music-list.vue中点击歌曲列表,进入播放器页面
store/actions.js中定义action,提交到mutation
//选择播放
export const selectPlay = function({commit, state}, {list, index}) {
commit(types.SET_SEQUENCE_LIST, list)
commit(types.SET_PLAYLIST, list) //播放列表
commit(types.SET_CURRENT_INDEX, index) //当前播放歌曲的索引
commit(types.SET_FULL_SCREEN, true) //全屏
commit(types.SET_PLAYING_STATE, true) //播放状态
}
在player.vue组件中,获取playlist所以组件v-show=true
...mapGetters{[
'playlist'
]}
1.audio
- playing:音频或视频已开始播放时触发
- error:在音频或视频加载发生错误时触发
- timeupdate:播放位置改变时触发[注意:播放和调整指示定位时都会触发]
- ended:音频或视频文件播放完毕后触发
<audio ref="audio" @playing="ready" @error="error" @timepudate="updateTime"
@ended="end"></audio>
2 vuex中获取数据
...mapGetters([
'fullScreen',
'playlist',
'currentSong',
'playing',
'currentIndex',
'mode',
'sequenceList'
])
3 在watch中定义currentSong playing
在点击歌曲列表之后,currentSong playing都有了相应的数据
- 获取相应的歌曲
- 获取歌词
watch: {
//在computed的getter中获取currentSong
currentSong(newSong, oldSong) {
if (!newSong.id || !newSong.url || newSong.id === oldSong.id) {
return
}
this.songReady = false
this.canLyricPlay = false
//获取歌词
if (this.currentLyric) {
//切换歌曲的时候,清除上一个歌曲的定时器,歌词跳动的bug
this.currentLyric.stop()
// 同时,将相关重置为null
this.currentLyric = null
this.currentTime = 0
this.playingLyric = ''
this.currentLineNum = 0
}
//播放歌曲
this.$refs.audio.src = newSong.url
this.$refs.audio.play()
//歌曲快速切换的时候,先清除定时器
clearTimeout(this.timer)
//若歌曲5s未播放,则认为超时,修改状态,确保可以切换歌曲
this.timer = setTimeout(() => {
this.songReady = true
}, 5000)
this.getLyric()
},
playing(newPlaying) {
if (!this.songReady) {
return
}
const audio = this.$refs.audio
this.$nextTick(function() {
newPlaying ? audio.play() : audio.pause()
})
},
fullScreen(newVal) {
if (newVal) {
setTimeout(() => {
this.$refs.lyricList.refresh()
this.$refs.progressBar.setProgressOffset(this.percent)
})
}
}
}
4.播放器功能按钮
<div class="operators">
<div class="icon i-left">
<i @click="changeMode" :class="iconMode"></i> //播放模式
</div>
<div class="icon i-left" :class="disableCls"> //前一首
<i @click="prev" class="icon-prev"></i>
</div>
<div class="icon i-center" :class="disableCls"> //播放/暂停按钮
<i @click="togglePlaying" :class="playIcon"></i>
</div>
<div class="icon i-right" :class="disableCls"> //下一首
<i @click="next" class="icon-next"></i>
</div>
</div>
4.1 样式
通过计算属性选择按钮的样式
computed: {
playIcon() { //播放/暂停按钮
return this.playing ? 'icon-pause' : 'icon-play'
},
disableCls() { //音乐是否加载完毕,加载完毕方可播放或者下一首或者上一首
return this.songReady ? '' : 'disable'
},
iconMode() { //播放模式
return this.mode === playMode.sequence ? 'icon-sequence' : this.mode === playMode.loop ? 'icon-loop' : 'icon-random'
},
判断歌曲加载状态audio相关状态
<audio ref="audio" @playing="ready" @error="error" @timepudate="updateTime"
@ended="end"></audio>
ready() {
clearTimeout(this.timer)
//监听audio的playing状态,可以播放的时候this.songReady=true,
//这个时候可以点击播放,下一首,上一首,快速切换歌曲
this.songReady = true
this.canLyricPlay = true
//保存播放历史
this.savePlayHistory(this.currentSong)
//如果歌曲的播放时间晚于歌词的出现,播放的时候需要同步歌词
if (this.currentLyric && !this.isPureMusic) {
this.currentLyric.seek(this.currentTime * 1000)
}
},
error() {
clearTimeout(this.timer)
//如果出现网络错误,或者地址不正确,那么this.songReady=false,不能进入ready(),所以不能
//点击播放,下一首,上一首,所以,在错误的时候,也应该this.songReady = true
this.songReady = true
},
//播放位置改变时触发[注意:播放和调整指示定位时都会触发]
updateTime(e) {
//歌曲播放时间进度
this.currentTime = e.target.currentTime
},
//歌曲播放完毕
end() {
this.currentTime = 0
if (this.mode === playMode.loop) {
//随机播放模式
this.loop()
} else {
this.next()
}
},
4.2 上一首方法
prev() {
//判断歌曲是否加载完毕
if (!this.songReady) {
return
}
if (this.playlist.length === 1) {
//处理边界情况:只有一首歌曲,循环播放
this.loop()
//return:因为后面this.songReady = false,会导致播放器按钮不可用
return
} else {
let index = this.currentIndex - 1
//点击上一首歌曲,到了第一首歌曲的时候,再点击上一首歌曲,则播放最后一首歌曲
if (index === -1) {
index = this.playlist.length - 1
}
//mutation改变状态currentIndex
this.setCurrentIndex(index)
//切换上一首歌曲后,如果未播放,则播放
if (!this.playing) {
this.togglePlaying()
}
}
this.songReady = false
},
4.3 下一首方法
next() {
//判断歌曲是否加载完毕
if (!this.songReady) {
return
}
if (this.playlist.length === 1) {
//处理边界情况:只有一首歌曲,循环播放
this.loop()
//return:因为后面this.songReady = false,会导致播放器按钮不可用
return
} else {
//点击下一首的时候,到了最后一首歌曲的时候,再点击,则播放第一首一首歌曲
let index = this.currentIndex + 1
if (index === this.playlist.length) {
index = 0
}
//mutation改变状态currentIndex
this.setCurrentIndex(index)
if (!this.playing) {
//如果未播放,则开始播放
this.togglePlaying()
}
}
this.songReady = false
},
4.4 播放模式:随机 循环 顺序
changeMode() {
//common/config.js中 默认是0:顺序 1:loop 2:random
const mode = (this.mode + 1) % 3
//同时修改vuex中的播放模式mode
this.setPlayMode(mode)
let list = null
if (mode === playMode.random) {
//随机播放,洗牌顺序列表
list = shuffle(this.sequenceList)
} else {
//非随机播放,则是顺序播放列表
list = this.sequenceList
}
//切换播放模式后,当前播放的歌曲索引可能发生变化,这个时候重置currentIndex
this._resetCurrentIndex(list)
//切换播放模式后 调用mutation更改播放列表
this.setPlayList(list)
},
_resetCurrentIndex(list) {
let index = list.findIndex((item) => {
return item.id === this.currentSong.id
})
//重置currentIndex
this.setCurrentIndex(index)
},
4.5 循环播放
//播放模式:循环播放
loop() {
//重置播放时间:0
this.$refs.audio.currentTime = 0
//开始播放
this.$refs.audio.play()
//vuex提交播放状态
this.setPlayingState(true)
if (this.currentLyric) {
//单曲循环的时候,歌词循环播放
this.currentLyric.seek(0)
}
},
4.6播放/暂停:按钮
togglePlaying() {
//如果未加载完毕,则不播放
if (!this.songReady) {
return
}
//vuex提交播放器播放状态
this.setPlayingState(!this.playing)
if (this.currentLyric) {
//歌曲暂停时,歌词暂停播放
this.currentLyric.togglePlay()
}
},
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。