轻量级音乐播放器搭建 6

轻量级音乐播放器搭建 6

 

现在把在music-controller组件中观察的state状态转移到music-player之中:

  music-player.vue
<script>
 ......
 import {mapState} from 'vuex'
 export default {
......
   computed: {
     ...mapState([
       'likeThisMusic',
       'playMode',
       'privateSongList'
    ])
  },
   methods: {
     ......
     togglePlaying (isPlaying) {
       console.log(isPlaying)
       if (isPlaying === true) {
         this.$refs.audio.play()
      } else {
         this.$refs.audio.pause()
      }
    },
     _handlePlayModeChanged () {
       console.log('PLAY MODE CHANGED!')
       console.log(this.$store.state.playMode)
    },
     _handleLikeThisMusicChanged () {
       console.log('LIKE THIS MUSIC CHANGED')
       console.log(this.$store.state.likeThisMusic)
    },
  },
   watch: {
     playMode () {
       this._handlePlayModeChanged()
    },
     likeThisMusic () {
       this._handleLikeThisMusicChanged()
    }
  }
}
</script>

如果播放状态改变了,那么要怎么修改才能实现对下一首歌的播放进行控制?在不大修改之前的代码的情况下,可以对当前的一个data变量做更改。因为一首歌结束之后,就是调用的_playDefaultMusic(currentMusicIndex)方法,那播放模式的改变其实就是对接下来的播放歌曲进行选择,那么就对currentMusicIndex做更改。但是这样有个问题是只能对接下来的那一首歌进行更改,而播放模式是一个长期的持续的状态。那可不可以有一个当前播放列表,每次切换格式的时候就对列表进行更新。比如说大前提是用户有私有的(播放模式只在播放私有列表有效,推荐FM中的播放模式无意义)若干播放列表。播放某个列表就是从某个状态切换成单曲循环,那么就是把当前的播放歌曲替换成当前的播放列表。

算了,太麻烦。我感觉还是要修改原来的代码。就是将_playDefaultMusic(currentMusicIndex)方法进行修改,在方法中通过三种不同的状态来调整下一个currentMusicIndex。所以更新函数如下:

  
_playDefaultMusic () {
 // 0代表单曲循环,1代表顺序播放,2代表随机播放
 if (this.$store.state.playMode === 2) {
   // 生成随机索引
   this.currentMusicIndex = Math.floor(Math.random() * this.defaultMusicList.length)
} else if (this.$store.state.playMode === 1) {
   if (this.currentMusicIndex === this.defaultMusicList.length - 1) {
     this.currentMusicIndex = 0
  } else {
     this.currentMusicIndex = this.currentMusicIndex + 1
  }
   ......
}
}

现在这个切换播放模式的功能就做完了,没有报错,但是现在还不能够验证是否可以正常使用。因为到现在为止还没有用户的概念,更别说登陆与用户的私人播放列表了。所以这个部分的测试需要之后再进行测试。

接下来是喜欢这首歌的功能,同样的这个功能也不能现在进行测试,所以现在先做能够完成的这一部分。

  
if (this.$store.state.likeThisMusic === true) {
 let thisMusic = Object.assign({},this.defaultMusicList[this.currentMusicIndex])
 // 将thisMusic对象push进用户的喜欢的歌曲的列表
} else {
 // 取消喜欢一首歌相对较为复杂,应当以歌曲id作为标记。
 // 再用户喜欢的歌曲的列表中找到对应id歌曲并进行删除
}

既然这个也还不能写,就进行下一个控制——上一首歌/下一首歌。下一首歌比较简单,首先做这个,因为是music-controller接受的控制,所以先回到这个组件的代码:

  
changeToNextMusic () {
 console.log('changToNextMusic')
 this.$emit('changeToNextMusic')
},

很简单,就是子组件在触发点击事件的时候执行此函数,然后这个函数触发一个自定义的changeToNextMusic事件来与父组件进行通信。现在回到父组件:

  
changeToNextMusic () {
 this._playDefaultMusic()
},

父组件监听changeToNextMusic事件,并执行changeToNextMusic函数,这个函数执行私有函数_playDefaultMusic,就可以完成切换到下一首歌的操作。这个很简单,然后是播放上一首歌,这个就比之前的下一首歌功能要复杂。因为需要有一个容器来储存之前播放的歌,但是有个问题就是当用户登陆与不登录的时候这个功能就不一样了。因为用户如果登陆之后,会有自己的播放记录。但是如果没有登陆,那么播放记录就是本地的播放记录。这还好,但是如果用户登陆之后又再下线,就要求必须有本地与用户两个播放记录。用户在线的话就把当前的歌曲添加到本地已播放歌曲与用户已播放记录,不在线的话就只将当前的歌曲添加到本地的已播放记录。这样的话就是现在先不用管用户的播放记录,现阶段只考虑本地播放记录。

所以就要实现一个播放记录,显然使用栈来储存比较好,由于这是一个h5应用,所以我觉得播放记录储存30条足够了。但是现阶段30条不好调试,所以我先将栈的容量设为5条。修改一个地方,之前的defaultMusicList更名为currentMusicList,这是因为现在的播放不是只针对那一个推荐的歌单,而是所有的歌曲列表,我们请求的是一个defaultMusicList,可以将这个列表赋给currentMusicList。播放记录我放到music-player组件中,实现如下:

  data () {
 return {
......
   history: [],
}
},

_playDefaultMusic () {
 ......
 // 更新本地历史纪录
 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])
}
 // 更新用户历史纪录
},

现在这样就是用户每自动切换到下一首歌或者是手动切歌到下一首歌,都会将这首新的歌添加到播放记录中。至于用户手动点击选择歌曲来播放歌曲的情况就到之后再考虑。然后我向控制播放记录的长度,那么当不断push进播放记录到了长度为6的时候,就将之前的元素去除。用shift、slice(1)等各种方法都不行,严格模式下不能使用这些函数,所以采用遍历,衰。

另外发现了两个问题,就是有时报错:

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

还有就是随机播放与播放记录这两个地方都有可能出现相同的歌曲,应当对有重复的情况进行处理。明天做,回宿舍了。

 

挖坑待填:

  1. 用户喜欢歌曲的添加与删除

  2. 用户播放记录的实现

  3. 更新用户播放记录。

参考链接:

  1. js 生成伪随机数

  2. js 生成真正的随机数

  3. assign 对象拷贝

posted @ 2017-10-12 17:29  虚几  阅读(748)  评论(0编辑  收藏  举报