輕量級音樂播放器搭建 7

輕量級音樂播放器搭建 7

 

今天是國慶節,4點多起牀去看升國旗儀式。自己是一件好事,參加儀式本身很受感動。可是感受本身身體真的是不行了,再也不像十七八歲甚至是前兩年了。參加完觀禮儀式,感受頭痛得要命,眼睛也發脹,趕勁回去補覺,從七點多一直又睡到十點多。仍是不行,到如今仍是頭疼。我確實睡得比較晚,但如今大環境都是這個樣,住在宿舍裏,早睡與晚睡只是五十步與一百步的區別。固然了,這多半是爲本身開脫,我仍是比較晚睡的。。好了,不說了,進入正題。api

昨天晚上出現了兩個問題,首先那個報錯的,我不知道爲何報錯顯示有新的請求:數組

  ncaught (in promise) DOMException: The play() request was interrupted by a new load request. https://goo.gl/LdLk22

我本身沒有請求這個地址,多是src的連接有一些轉發什麼的。也定位不到報錯的位置,就是在快速切換歌曲的時候有概率出現這種報錯,我看網上關於這個問題討論的也很少,解決方法更沒有找到有用的。折騰了半天,放棄了,如今不影響正常播放,那就先這樣吧。promise

另一個問題就是播放記錄或者是播放列表的重複的問題。我想抽象出一個判斷是否重複的函數,再播放下一首歌的時候與添加播放記錄的時候進行調用,而後判斷以後再進行下一步的播放或者push進記錄。哦,補充一下若是播放下一首的歌曲是重複的那麼這種狀況是在單曲循環的時候容許的,因此也就是說播放記錄的重複檢查也是有必要的。在common目錄中新建js目錄,用於儲存通用的非api請求的js模塊。其中新建isDuplicated.js文件,判斷歌曲時候重複能夠判斷歌曲的id屬性是否相等:瀏覽器

  
export default function isDuplicated(firstSong, secondSong) {
 return firstSong.id === secondSong.id
}

而後修改_playDefaultMusic()與其餘相關代碼:框架

    ......
 import isDuplicated from 'js/isDuplicated'

_playDefaultMusic () {
 // 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])) {
     this._playDefaultMusic()
  }            
}
 ......

寫到這裏,插個內容。如今項目的控制檯中有不少的log,可是看起來比較亂,也很差快速尋找有用的信息,因此能夠在服務端安裝一個插件colors或者chalk。若是是在瀏覽器的控制檯,但是使用格式化輸出。dom

而後就是對播放列表的去重,這個去重是不論什麼播放模式都須要去重的,單曲循環模式不能一直放好多的同一首音樂在已播放列表中。可是,蛋疼的是,嚴格模式下數組操做方法幾乎都不能用,因而進行如下修改,而且將更新已播放列表代碼抽象到一個新的函數中而不是在_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屬性的請求。不過又有一個新的問題,當沒有歷史紀錄或者是歷史紀錄被不斷地上一首切換到了盡頭的時候,這時候應當對上一首歌的切換進行限制。以下:this

  
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]
  }
},

說實話如今代碼已經開始有些凌亂了,是我沒有先打好框架的緣由。以前寫天氣預報應用就很好,先寫好框架,再寫具體的實現。

 

 

參考連接:

  1. console 對象

  2. console 打印樣式

  3. ES6 默認參數

相關文章
相關標籤/搜索