微信小程序音樂播放


  最近在寫一個艾美食艾音樂的微信小程序,其中有用到音樂播放的功能,基本播放切換功能已經實現,但是在反復切換歌曲、重新進入歌曲以及單曲循環、列表循環的測試過程中還是發生了bug,特此寫一篇文章,捋一下思路.(功能寫到后面小程序官方文檔將音頻這一塊全都更新了...)

  坑點:由於小程序主體部分沒有app.wxml,這就導致小程序不能寫一些公共的頁面結構,如果有相同的部分,只能封裝成組件再引入.

  在我們點擊歌曲列表中的某首歌的時候,會進入音樂播放界面,當我們退出音樂播放界面,歌曲仍然繼續播放,但此時由於退出當前路由,頁面data中的數據也已被銷毀,當我們再次進入播放界面相當於重新進行頁面加載,所以需要我們進行分情況判斷,播放歌曲變的較為復雜.

  一.存放公共數據

    在我們進入音樂播放界面之前要存一下:

      當前專輯信息:album(Object)

      當前播放列表:playList(Array)

      當前播放歌曲的index:playIndex(Number)

      播放模式:mode(String)

      封面旋轉的角度:imgRotate(Number)

   

// app.js
globalData: { album: null,
// 當前專輯信息 playList: [], // 當前播放列表 playIndex: 0, // 當前播放歌曲index mode: 'multiple', // 循環模式 multiple: 循環播放, single: 單曲循環 imgRotate: 0, // 封面旋轉角度
}

 

  二.專輯列表

    在專輯列表中點擊某個專輯,進入該專輯的歌曲列表,同時將 該專輯的信息 存入globalData.

// music.js
gotoSongList(e) { let item
= e.currentTarget.dataset.type app.globalData.album = item // 將專輯信息存入globalData wx.navigateTo({ url: '../songlist/songlist' }) }

  三.歌曲列表

    在歌曲列表中點擊播放某首歌時,進入歌曲播放界面,同時將 該專輯的歌曲列表、當前播放歌曲的index 存入globalData.

// songlist.js
// 播放歌曲
  play(e) {
    app.globalData.playList = this.data.songList
    let index = e.currentTarget.dataset.index
    app.globalData.playIndex = index
    let url = '../player/player'
    wx.navigateTo({
      url: url
    })
}

  四.歌曲播放頁面

    需要在data中存放一下信息:

      當前歌曲信息:item(Object)

      歌曲解析后的歌詞:parseLyric(String)

      當前播放進度點的歌詞:lineLyric(String)

      播放模式:mode(String)

      封面旋轉的角度:imgRotate(Number)

      進度條的值:SliderValue(Number)

      音頻的長度:duration(Number)

      音頻的播放位置:currentPosition(Number)

      播放狀態:playStatus(Boolean)

const app = getApp();
var Base64 = require('../../utils/base64.js').Base64
var Lyric = require('../../utils/lyric-parse.js')
Page({
  data: {
    item: {}, // 當前歌曲信息
    parseLyric: '', // 歌曲解析后的歌詞
    lineLyric: '', // 當前播放進度點的歌詞
    mode: '', // 播放模式
    imgRotate: 0, // 封面旋轉的角度
    sliderValue: 0, // 進度條的值
    duration: 0, // 音頻的長度(單位:s)
    currentPosition: 0, // 音頻的播放位置(單位:s)
    playStatus: 0, // 播放狀態
    timee: 0, // 定時器 根據歌曲進度改變slider進度
    coverImg: '', // 封面圖片
    isDel: false, // 當前列表是否只有一首歌曲
  },
  onLoad() {
    let item = app.globalData.playList[app.globalData.playIndex]
    let album = app.globalData.album
    // 獲取背景音頻信息
    const backgroundAudioManager = wx.getBackgroundAudioManager()
    console.log(backgroundAudioManager, 'backgroundAudioManager')
    if (backgroundAudioManager.src == item.src) { // 繼續聽歌
      console.log('繼續聽歌')
    } else { // 播放新歌
      app.globalData.imgRotate = 0
      console.log('播放新歌')
      backgroundAudioManager.title = item.name
      backgroundAudioManager.epname = album.name
      backgroundAudioManager.singer = item.author
      backgroundAudioManager.coverImgUrl = album.poster
      // 設置了 src 之后會自動播放
      backgroundAudioManager.src = item.src
    }
    let lyric = Base64.decode(item.lyric)
    this.setData({
      item: item,
      coverImg: album.poster,
      playStatus: !backgroundAudioManager.paused,
      duration: this.stotime(backgroundAudioManager.duration),
      currentPosition: this.stotime(backgroundAudioManager.currentTime),
      parseLyric: new Lyric(lyric, this.handleLyric),
      mode: app.globalData.mode,
      imgRotate: app.globalData.imgRotate
    })
    this.data.parseLyric.seek(backgroundAudioManager.currentTime*1000)
    console.log(this.data.playStatus, 'playStatus')
    if (backgroundAudioManager.paused) {
      this.data.parseLyric.togglePlay()
    } else if (!this.data.timee) {
      this.toRotate()
    }
    backgroundAudioManager.onPlay(this.onPlay) // 監聽背景音頻播放事件
    backgroundAudioManager.onPause(this.onPause) // 監聽背景音頻暫停事件
    backgroundAudioManager.onTimeUpdate(this.onTimeUpdate) // 監聽背景音頻播放進度更新事件
    backgroundAudioManager.onEnded(this.onEnded) // 監聽背景音頻自然播放結束事件
    wx.setNavigationBarTitle({
      title: item.name
    })
    console.log(app.globalData.playList.length, 'app.globalData.playList.length')
    if (app.globalData.playList.length == 1) {
      this.setData({
        isDel: true
      })
    }
  },
  handleLyric({lineNum, txt}) { // 歌詞回調
    console.log(lineNum, txt, 'txt')
    this.setData({
      lineLyric: txt
    })
  },
  onPlay() {
    const backgroundAudioManager = wx.getBackgroundAudioManager()
    console.log('onPlay')
    console.log(backgroundAudioManager.duration, 'backgroundAudioManager.duration')
    this.setData({
      playStatus: true
    })
    this.data.parseLyric.seek(backgroundAudioManager.currentTime*1000)
    this.toRotate()
  },
  onPause() {
    clearInterval(this.data.timee)
    this.data.parseLyric.stop()
    console.log('onPause')
    this.setData({
      playStatus: false
    })
  },
  switch() { // 切換歌曲播放狀態
    if (this.data.playStatus) { // 切換為暫停狀態
      const backgroundAudioManager = wx.getBackgroundAudioManager()
      backgroundAudioManager.pause()
    } else { // 切換為播放狀態
      const backgroundAudioManager = wx.getBackgroundAudioManager()
      backgroundAudioManager.play()
    }
  },
  onTimeUpdate() {
    const backgroundAudioManager = wx.getBackgroundAudioManager()
    let sliderValue = backgroundAudioManager.currentTime / backgroundAudioManager.duration * 100
    this.setData({
      currentPosition: this.stotime(backgroundAudioManager.currentTime),
      sliderValue: sliderValue,
      duration: this.stotime(backgroundAudioManager.duration)
    })
    // this.data.parseLyric.seek(backgroundAudioManager.currentTime*1000)
  },
  toRotate() {
    this.data.timee && clearInterval(this.data.timee)
    this.data.timee = setInterval(() => {
      app.globalData.imgRotate  = app.globalData.imgRotate + 0.8
      this.setData({
        imgRotate: app.globalData.imgRotate
      })
    }, 35)
  },
  onEnded() {
    console.log('onEnded')
    this.setData({
      playStatus: false
    })
    if (this.data.mode == 'multiple') {
      this.cutNext()
    } else {
      const backgroundAudioManager = wx.getBackgroundAudioManager()
      // 設置了 src 之后會自動播放
      backgroundAudioManager.src = this.data.item.src
    }
  },
  slideChange(e) { // 拖動滑塊
    let value = e.detail.value
    this.setData({
      sliderValue: value
    })
    const backgroundAudioManager = wx.getBackgroundAudioManager()
    let currentTime = (value / 100) * backgroundAudioManager.duration
    backgroundAudioManager.seek(currentTime)
    this.data.parseLyric.seek(currentTime*1000)
  },
  cutPrev() { // 上一首
    this.delSongChange('prev')
  },
  cutNext() { // 下一首
    this.delSongChange('next')
  },
  delSongChange(type) { // 切換歌曲
    if (this.data.duration !== 0 && !this.data.isDel) {
      if (app.globalData.playList.length > 1) {
        clearInterval(this.data.timee)
      }
      this.data.duration = 0
      this.data.parseLyric.stop()
      if (type == 'prev') {
        if (app.globalData.playIndex > 0) {
          app.globalData.playIndex --
        } else {
          app.globalData.playIndex = app.globalData.playList.length - 1
        }
      } else {
        if (app.globalData.playIndex < app.globalData.playList.length - 1) {
          app.globalData.playIndex ++
        } else {
          app.globalData.playIndex = 0
        }
      }
      let item = app.globalData.playList[app.globalData.playIndex]
      wx.setNavigationBarTitle({
        title: item.name
      })
      const backgroundAudioManager = wx.getBackgroundAudioManager()
      backgroundAudioManager.title = item.name
      backgroundAudioManager.singer = item.author
      // 設置了 src 之后會自動播放
      backgroundAudioManager.src = item.src
      let lyric = Base64.decode(item.lyric)
      this.setData({
        item: item,
        playStatus: !backgroundAudioManager.paused,
        parseLyric: new Lyric(lyric, this.handleLyric)
      })
      this.data.parseLyric.seek(backgroundAudioManager.currentTime*1000)
      console.log(this.data.playStatus, 'playStatus')
      if (backgroundAudioManager.paused) {
        this.data.parseLyric.togglePlay()
      }
    }
  },
  // 改變播放模式
  changeMode() {
    if (this.data.mode == 'multiple') {
      this.setData({
        mode: 'single'
      })
    } else {
      this.setData({
        mode: 'multiple'
      })
    }
    app.globalData.mode = this.data.mode
  },
  // 時間格式轉換
  stotime(s) {
    let t = ''
    if (s > -1) {
      let min = Math.floor(s / 60) % 60;
      let sec = Math.floor(s) % 60
      if (min < 10) { t += '0' }
      t += min + ':'
      if (sec < 10) { t += '0' }
      t += sec
    }
    return t
  },
  onUnload() { // 頁面卸載
    const backgroundAudioManager = wx.getBackgroundAudioManager()
    backgroundAudioManager.onTimeUpdate()
    backgroundAudioManager.onPlay()
    backgroundAudioManager.onPause()
    this.data.parseLyric.stop()
    clearInterval(this.data.timee)
  },
})

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM