One.
缺陷:当打开播放器快速切换歌曲时,按下暂停播放,发现歌词和背景音乐都仍在播放,这显示是不符合预期的。
原因:代码watch currentSong的变化以后做清理操作,然后执行audio.play()和获取歌曲。这里就存在一个问题——当我们快速切换的时候,canplay事件触发产生的相关操作可能在1s内就完成,也就是说,有可能先执行audio.pause()再执行watch时的audio.play(),所以就导致显示为暂停,但是它歌曲仍然在播放。
解决:因为我们是延时执行,但是在切换的时候,currentSong是快速变化的,我们要保证setTimeout里的逻辑只执行一次。
clearTimeout(this.timer); this.timer = setTimeout(() => { this.$refs.audio.play().catch((error) => { this.togglePlaying(); // eslint-disable-next-line no-alert alert('播放出错,暂无该歌曲资源'); }, 1000); // 这里不直接调用currentSong.getLyric() this.getLyric();
这样就可以保证无论currentSong变化多少次,只执行最后一次的setTimeout的,之前的setTimeout都会被清除掉。
但是光有这个逻辑也是不够的,还要修改ready的触发事件canplay改为play,就不能很快切换,保证先执行play才会触发ready,然后audio.pause肯定在这之后执行。
<audio ref="audio" :src="currentSong.url" @play="ready" @error="error" @timeupdate="updateTime" @ended="end"></audio>
Two.
缺陷:在多次切换过程中,还有可能出现歌词混乱对应不上歌曲的问题。
原因:因为getLyric方法是异步操作,当它执行到回调获取歌词的时候我们就有可能切换到下一首歌了,之前的歌词又会被new一次,相当于new了两次。
解决:我们要加个判断:当前的歌词内容是否等于获取到的歌词内容,如果相等就什么都不做。这样就保证了歌词不会乱掉。
this.currentSong.getLyric().then((lyric) => { if (this.currentSong.lyric !== lyric) { return; } this.currentLyric = new Lyric(lyric, this.handleLyric); if (this.playing) { this.currentLyric.play(); } }).catch(() => { this.currentLyric = null; this.playingLyric = ''; this.currentLineNum = 0; });
Three.
缺陷:如果当前播放列表只有一首歌的时候,点下一首,按钮不会再触发ready。
原因:列表长度为1时,会调用loop方法,loop会把currentTime切到开始,play事件就不会触发了。
解决:在调用loop时直接return。
next() { // 如果没有ready好的话就直接返回 if (!this.songReady) { return; } if (this.playlist.length === 1) { this.loop(); return; } else { ...... } this.songReady = false; },