轻量级音乐播放器搭建 7
Posted 虚几
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了轻量级音乐播放器搭建 7相关的知识,希望对你有一定的参考价值。
今天是国庆节,4点多起床去看升国旗仪式。本身是一件好事,参加仪式自己很受感动。但是感觉自己身体真的是不行了,不再像十七八岁甚至是前两年了。参加完观礼仪式,感觉头痛得要命,眼睛也发胀,赶劲回去补觉,从七点多一直又睡到十点多。还是不行,到现在还是头疼。我确实睡得比较晚,但现在大环境都是这个样,住在宿舍里,早睡与晚睡只是五十步与一百步的区别。当然了,这多半是为自己开脱,我还是比较晚睡的。。好了,不说了,进入正题。
昨天晚上出现了两个问题,首先那个报错的,我不知道为什么报错显示有新的请求:
ncaught (in promise) DOMException: The play() request was interrupted by a new load request. https://goo.gl/LdLk22
我自己没有请求这个地址,可能是src的链接有一些转发什么的。也定位不到报错的位置,就是在快速切换歌曲的时候有几率出现这种报错,我看网上关于这个问题讨论的也不多,解决方法更没有找到有用的。折腾了半天,放弃了,现在不影响正常播放,那就先这样吧。
另外一个问题就是播放记录或者是播放列表的重复的问题。我想抽象出一个判断是否重复的函数,再播放下一首歌的时候与添加播放记录的时候进行调用,然后判断之后再进行下一步的播放或者push进记录。哦,补充一下如果播放下一首的歌曲是重复的那么这种情况是在单曲循环的时候允许的,所以也就是说播放记录的重复检查也是有必要的。在common目录中新建js目录,用于储存通用的非api请求的js模块。其中新建isDuplicated.js文件,判断歌曲时候重复可以判断歌曲的id属性是否相等:
export default function isDuplicated(firstSong, secondSong) {
return firstSong.id === secondSong.id
}
然后修改_playDefaultMusic()与其他相关代码:
写到这里,插个内容。现在项目的控制台中有很多的log,但是看起来比较乱,也不好快速寻找有用的信息,所以可以在服务端安装一个插件colors或者chalk。如果是在浏览器的控制台,可是使用格式化输出。
然后就是对播放列表的去重,这个去重是不论什么播放模式都需要去重的,单曲循环模式不能一直放好多的同一首音乐在已播放列表中。但是,蛋疼的是,严格模式下数组操作方法几乎都不能用,于是进行以下修改,并且将更新已播放列表代码抽象到一个新的函数中而不是在_playDefaultMusic函数中:
_updateHistory () {
// 判断目前的歌曲是否与本地记录的最后一条有重复,判断播放记录是否为空
if (this.history.length !== 0 &&
isDuplicated(this.currentMusicList[this.currentMusicIndex], this.history[this.history.length - 1])) {
console.log(‘%cDUPLICATED‘,"color: red; background: yellow; font-size: 24px;")
} else {
// 更新本地历史纪录
if (this.history.length === this.historyLength) {
for (let i = 1; i < this.historyLength; i++) {
this.history[i - 1] = this.history[i]
}
this.history[this.historyLength - 1] = this.currentMusicList[this.currentMusicIndex]
} else {
this.history.push(this.currentMusicList[this.currentMusicIndex])
}
}
console.log(this.history)
// 更新用户历史纪录
},
弄完了以上的东西,就改继续做上一首歌的切换了。写到这里就发现代码可以优化,可以更加的模块化,比如说之前的播放下一首歌是调用了_playDefaultMusic方法,方法中计算索引,再播放对应索引的音乐。那么现在这个播放上一首歌可以利用播放对应索引的音乐,不过计算索引就不再是使用这个方法中一直使用的计算索引的代码,而是通过其他的途径获取,所以现在的这个私有playDefaultMusic方法可以分成两个函数。所以对此函数进行如下的修改:
_getNewIndex () {
// 0代表单曲循环,1代表顺序播放,2代表随机播放
let lastMusicIndex = this.currentMusicIndex
if (this.$store.state.playMode === 2) {
// 生成随机索引
this.currentMusicIndex = Math.floor(Math.random() * this.currentMusicList.length)
} else if (this.$store.state.playMode === 1) {
if (lastMusicIndex === this.currentMusicList.length - 1) {
this.currentMusicIndex = 0
} else {
this.currentMusicIndex = lastMusicIndex + 1
}
}
// 在随机播放的时候判断时候为重复歌曲
if(this.$store.state.playMode === 2) {
if (isDuplicated(this.currentMusicList[lastMusicIndex], this.currentMusicList[this.currentMusicIndex])) {
console.log(‘the music is duplicated to the last one‘);
this._playDefaultMusic()
}
}
this._updateHistory()
},
_changeMusicSrc (this.currentMusicList[this.currentMusicIndex].id) {
getMusicUrl(id)
.then((res) => {
console.log(‘开始获取歌曲 ‘ + this.currentMusicList[this.currentMusicIndex].name + ‘ 播放地址‘)
this.currentMusicUrl = res.data[0].url
console.log(‘获取到歌曲播放地址为 ‘ + this.currentMusicUrl)
})
},
_playDefaultMusic () {
this._getNewIndex()
this._changeMusicSrc()
},
其实就是把代码换了一下位置。然后稍微修改一下这个_changeMusicSrc函数,让他可以接受一个歌曲id参数,如果有参数的话就使用id参数,没有的话就使用默认参数。可以使用ES6的新特性——默认参数,当让这只是一个语法糖,自己实现也可以。
然后这样就可以对切换到上一首歌愉快的实现了,分两步,第一步获得上一首歌的id,第二部根据id进行歌曲url也就是src属性的请求。不过又有一个新的问题,当没有历史纪录或者是历史纪录被不断地上一首切换到了尽头的时候,这时候应当对上一首歌的切换进行限制。如下:
cutToPrevSong () {
console.log(‘cutToPrevSong‘)
let prevMusic = this._getPrevMusic()
let id = prevMusic ? prevMusic.id : null
this._changeMusicSrc(id)
},
_getPrevMusic () {
if (this.history.length === 0) {
return null
} else {
return this.history[this.history.length - 1]
}
},
不过这样经过实验是切不回去上一首歌的,下图是对切换到上一首歌进行两次请求的日志:
因为逻辑上取的是history这个栈的栈顶元素,然而再播放当前的music的时候就已经把当前的音乐信息push进了history栈。所以无论怎么切换,结果都是当前的歌曲。所以把代码中对数组索引的操作的数字0与1改为1与2。然后这样就完了吗?没有!因为现在的做法是仅仅将上一首歌曲的url换了过来。但是其他的一切都没变,包括currentMusicIndex,专辑图片的地址等等。所以以上的方法不是一个好方法,想了想这里还略微有些复杂。必须分为三种播放模式讨论,因为牵涉到currentMusicIndex,所以不分类讨论会很混乱。大前提是有一个播放列表与一个播放记录,首先讨论单曲循环,这个时候的上一首是切换到播放列表中的上一首再进行单曲循环;然后是顺序播放(如果是推荐FM的这种歌单而不是本地播放列表,也应当算作并且应当使用顺序播放模式),这个时候不应当走播放记录,而是应当与单曲循环一样,将currentMusicIndex移动到列表中的上一首歌;最后是随机播放,这个时候应当是使用播放记录,但是播放之前的歌曲要牵扯到播放记录修改也就比较麻烦,严格模式还不支持数组的操作,所以这就不好实现。或者是我的随机播放的方法一开始就想错了,不应当是每次对索引进行随机选取,而是应当对整个一个播放列表随机打乱顺序然后顺序播放,这样的话实现上一首歌会简单一些。那现在先不考虑随机播放的上一首歌的问题,以后有时间再改。实现如下:
cutToPrevSong () {
console.log(‘cutToPrevSong‘)
// let prevMusic = this._getPrevMusic()
// let id = prevMusic ? prevMusic.id : null
// this._changeMusicSrc(id)
let lastMusicIndex = this.currentMusicIndex
if (lastMusicIndex === 0) {
this.currentMusicIndex = this.currentMusicList.length - 1
} else {
this.currentMusicIndex = lastMusicIndex - 1
}
this._changeMusicSrc()
this._updateHistory()
},
_getPrevMusic () {
if (this.history.length === 1) {
return null
} else {
return this.history[this.history.length - 2]
}
},
说实话现在代码已经开始有些凌乱了,是我没有先打好框架的原因。之前写天气预报应用就很好,先写好框架,再写具体的实现。
参考链接:
以上是关于轻量级音乐播放器搭建 7的主要内容,如果未能解决你的问题,请参考以下文章