使用vue实现自己音乐播放器仿网易云 移动端 (audio、播放、暂停、上一首、下一首、展示评论、音量控制、进度条拖拽)

1.播放 暂停功能的实现

这是audio标签

<audio @timeupdate="updateTime" @canplay="getDuration" @ended="ended" :src="musicUrl" ref="audio"></audio>

这是播放和暂停图标

<div class="pause" v-show="isPlaying" @click="pauseSong"><i class="fa fa-pause"></i></div>
<div class="play" v-show="!isPlaying" @click="playSong"><i class="fa fa-play"></i></div>

 

播放和暂停事件我们通过 this.$refs.audio.play()this.$refs.audio.pause()来进行控制,并切换isPlaying的值来改变图标的显示。设置 this.$refs.audio.autoplay= true 可实现歌曲自动播放

中间圆形图片的旋转和暂停是通过添加类名控制:
css样式如下:

.cd.rotate img{
  animation: rotateIMG 15s linear infinite;
}
.cd.rotatePause img{
 animation-play-state:paused;
  -webkit-animation-play-state:paused; /* Safari 和 Chrome */
}
@keyframes rotateIMG{
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

html结构如下:

<div class="cd" v-show="show" @click="show = !show" ref="cd">
   <img :src="playingSong.blurPicUrl" width="60%">
 </div>

 

  • 1
  • 2
  • 3

js控制如下:

// 播放时
this.$refs.cd.classList.add('rotate')
if (this.$refs.cd.classList.contains('rotatePause')) this.$refs.cd.classList.remove('rotatePause')

// 暂停时
this.$refs.cd.classList.add('rotatePause')

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2. 上一首 下一首功能的实现

要实现这个功能我们就要拿到当前歌曲列表的所有数据。我请求的是网易云的接口,将数据存在vuex里面。我们只需通过切换数组索引即可达到切换歌曲。
歌曲列表是通过遍历出来的,所以我们可以给节点加上data-index属性。结果像下面这样
邓碧寒我喜欢你

接下来点击的时候我们把当前data-index存到localStorage里面,之后在上一首/下一首的点击事件里 – 或者 ++进行切换,并做边界值判断 代码如下:

prevSong () { // 播放上一首歌曲
  localStorage.curSongPlayIndex--
   if (localStorage.curSongPlayIndex < 0) localStorage.curSongPlayIndex = this.$store.state.songPlayList.length - 1
   this.playingSong = this.$store.state.songPlayList[JSON.parse(localStorage.curSongPlayIndex)]
   this.loadMusic() // 加载音乐地址 加载歌词 加载喜欢状态 加载音乐评论
   this.autoPlaySong() // 点击之后歌曲或自动播放
 }

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3.进度条显示 时间显示 进度条拖拽功能实现

3.1获取音乐总时长

canplay钩子函数拿到总时长

getDuration () { // canplay时获取音频总时长
  this.duration = this.$refs.audio.duration
  this.allTime = this.formatTime(this.$refs.audio.duration)
},

 

  • 1
  • 2
  • 3
  • 4

注意:时间获取出来是秒。我们要显示的是mm:ss格式。所以 this.duration存的时间是秒 this.allTime存的时间是格式化之后的
formatTime函数代码如下:

formatTime (time) {
 if (time === 0) {
    this.curTime = '00:00'
    return
  }
  const mins = Math.floor(time / 60) < 10 ? `0${Math.floor(time / 60)}` : Math.floor(time / 60)
  const sec = Math.floor(time % 60) < 10 ? `0${Math.floor(time % 60)}` : Math.floor(time % 60)
  return `${mins}:${sec}`
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.2拿到当前时间 更新进度条

timeupdate钩子函数获取当前播放时间

updateTime (e) { // timeupdate时获取当前播放时间
 const { currentTime } = e.target
 this.currentTime = currentTime
 this.curTime = this.formatTime(currentTime)
 this.updateProgress(this.currentTime, this.duration)
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个地方同样的this.currentTime是当前时间(秒),this.curTime是格式之后的分秒格式
下一步我们就要更新进度条了,得到 当前时间和总时间 的比值 来更新进度条的宽度和小圆点距离左边的距离

updateProgress (currentTime, duration) { // 更新进度条
 this.precent =  `${((currentTime / duration) * 100).toFixed(5)}%`
},

 

  • 1
  • 2
  • 3
<div class="progress" @click="clickProgress($event)" ref="progress">
  <div class="line" :style="{width: `${precent}`}"></div>
  <div class="dot" :style="{left: `${precent}`}" @touchstart='dotStart' @touchmove='dotMove' @touchend='dotEnd'></div>
</div>

 

  • 1
  • 2
  • 3
  • 4

3.3进度条点击播放 拖拽播放

clickProgress方法里这样写

clickProgress (event) { // 点击进度条时 更新音频时间和进度条
 const e = event || window.event
 const position = e.clientX - e.currentTarget.offsetLeft // 当前点击的位置
 const progressWidth = this.$refs.progress.offsetWidth // 进度条总宽度
 this.$refs.audio.currentTime = ((position / progressWidth) * this.duration) // 设置当前音频的播放时间
 this.updateProgress(((position / progressWidth) * this.duration), this.duration)
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这样就实现了点击进度条播放。

下面是拖拽功能的实现,使用原生的touchstart touchmove touchend来监听。
touchmove时,获取小圆点拖动到距离进度条左边的距离,并实施更新进度条

touchMove(e) {
 // 移动的距离
  let moveX = e.touches[0].pageX - 83 // 83是进度条距离浏览器的距离
  // 进度条的宽度
  const progressWidth = this.$refs.progress.offsetWidth
  if (moveX >= progressWidth) moveX = progressWidth // 边界值判断

  this.$refs.audio.currentTime = ((moveX / progressWidth) * this.duration) // 实时更新播放时间
  this.updateProgress(((moveX / progressWidth) * this.duration), this.duration) // 更新进度条
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

touchend时播放歌曲

touchEnd(e) {
  this.playSong() //调用播放歌曲方法
  this.isPlaying = true
},

 

  • 1
  • 2
  • 3
  • 4

4.评论区的展示

在这里插入图片描述
比较简单 直接遍历得到的数据然后渲染就行。只是在切换歌曲时要把评论区给隐藏掉

完整代码

HTML

<template>
<div style="height: 100%">
  <div class="blur-container" :style="{ 'background-image': `url(${playingSong.blurPicUrl})` }">
  </div>
  <div class="play-container">
    <goBack :showGoBack='showGoBack'/>
    <div class="cd" v-show="show" @click="show = !show" ref="cd">
      <img :src="playingSong.blurPicUrl" width="60%">
    </div>
    <div class="lyrics" v-show="!show" @click="show = !show">
      <div class="volume">
        <i class="fa fa-volume-up" v-show="!isMuted" @click.stop.prevent="muted(true)"></i>
        <i class="fa fa-volume-off" v-show="isMuted" @click.stop.prevent="muted(false)"></i>
        <div class="volumeRange"><input type="range" min="0" max="100" v-model="volume" step="1" @input="handleVolumeChange"></div>
      </div>
      <div class="lyrics-container">
        <ul ref="lyricUL">
          <li v-for="(item, i) in lyricsObjArr" :style="{color: lyricIndex === i ? 'skyblue' : '#ded9d9'}" :key="item.uid" :data-index='i' ref="lyric">{{item.lyric}}</li>
        </ul>
      </div>
    </div>

    <!-- 下方控件 -->
    <div class="bottom">
      <div class="bottom-line1">
        <div class="like" @click="toggleLikeMusic" v-show="!like"><i class="fa fa-heart-o"></i></div>
        <div class="like like-yes" @click="toggleLikeMusic(false)" v-show="like"><i class="fa fa-heart"></i></div>
        <div class="download" @click="download"><i class="fa fa-download"></i></div>
        <div class="comment" @click="showComment"><i class="fa fa-commenting-o"></i></div>
      </div>
      <div class="bottom-progress">
        <div class="curTime">{{curTime}}</div>
        <div class="progress" @click="clickProgress($event)" ref="progress">
          <div class="line" :style="{width: `${precent}`}"></div>
          <div class="dot" :style="{left: `${precent}`}" @touchstart='dotStart' @touchmove='dotMove' @touchend='dotEnd'></div>
        </div>
        <div class="allTime">{{allTime}}</div>
      </div>
      <div class="bottom-controls">
        <div class="prev" @click="prevSong"><i class="fa fa-step-backward"></i></div>
        <div class="pause" v-show="isPlaying" @click="pauseSong"><i class="fa fa-pause"></i></div>
        <div class="play" v-show="!isPlaying" @click="playSong"><i class="fa fa-play"></i></div>
        <div class="next" @click="nextSong"><i class="fa fa-step-forward"></i></div>
      </div>
    </div>

    <!-- autio标签 -->
    <audio @timeupdate="updateTime" @canplay="getDuration" @ended="ended" :src="musicUrl" id="audio" ref="audio"></audio>
    <comment :showCommentPanel='showCommentPanel' @getMoreComment='getMoreComment' @likeComment='toggleLikeComment'/>
  </div>
</div>
</template>

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

CSS

<style scoped lang="scss">
.blur-container{
  width: 100%;
  height: 100%;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  background-attachment: fixed;
  position: relative;
  z-index: 1;
  filter: blur(50px);
}
.play-container{
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background: rgba(0, 0, 0, .2);
}
.cd{
  height: 60%;
  display: flex;
  align-items: center;
  justify-content: center;
  img{
    border-radius: 50%;
  }
}
.cd.rotate img{
  animation: rotateIMG 15s linear infinite;
}
.cd.rotatePause img{
 animation-play-state:paused;
  -webkit-animation-play-state:paused; /* Safari 和 Chrome */
}
.lyrics{
  height: 70%;
  box-sizing: border-box;
  padding: 0 5% 20% 5%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: #fff;
  .volume{
    display: flex;
    align-items: center;
    i{
      margin-right: 20px;
    }
    .volumeRange{
      width: 100%;
    }
  }
  &-container{
    height: 75%;
    font-size: 16px;
    overflow: hidden;
    ul{
      text-align: center;
      li{
        color: #ded9d9;
        line-height: 30px;
      }
      li.active{
        color: skyblue;
      }
    }
  }
}
.bottom{
  height: 20%;
  color: #fff;
  &-line1{
    font-size: 30px;
    display: flex;
    align-items: center;
    justify-content: space-around;
    .like-yes{
      i{
        color: #C20C0C;
      }
    }
  }
  &-progress{
    padding: 0 5%;
    margin: 5% 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    .progress{
      height: 2px;
      background-color: #fff;
      width: 70%;
      position: relative;
      .line{
        position: absolute;
        left: 0;
        top: 0;
        height: 2px;
        background-color: skyblue;
        transition: width .1s;
      }
      .dot{
        width: 14px;
        height: 14px;
        border-radius: 50%;
        position: absolute;
        top: -6px;
        background-color: #ccc;
        transition: left .1s;
      }
    }
  }
  &-controls{
    // padding: 0 5%;
    display: flex;
    align-items: center;
    justify-content: space-around;
    font-size: 30px;
  }
}
</style>

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127

JavaScript

<script>
import goBack from '@components/public/goBack'
import comment from '@/components/comment/comment'
export default {
  props: {
  },
  data () {
    return {
      showGoBack: {
        title: '',
        show: 1,
        path: '',
        style: { padding: '5% 0 0 5%', color: '#fff', 'box-sizing': 'border-box' }
      },
      showCommentPanel: {
        show: false
      },
      playingSong: {}, // 正在播放的歌曲信息
      show: true, // 控制cd和lyrics的显示 默认显示cd
      isPlaying: false, // 播放和暂停状态
      musicUrl: '', // 音乐地址
      curTime: '00:00', // 当前播放时间,格式化之后的
      allTime: '00:00', // 当前音频总时长,格式化之后的
      duration: 0, // 音频总时长,单位秒
      currentTime: 0, // 音频当前播放时间, 单位秒
      precent: '0%', // 当前播放进度百分比
      touchInfo: {}, // 原点滑动时的位置信息
      lyrics: {}, // 歌词 中英文
      lyricsObjArr: [], // 处理之后的歌词 包含时间和歌词
      curMsTime: '', // 当前音频播放的时分毫秒
      like: false, // 是否喜欢当前歌曲 默认为不喜欢
      lyricIndex: '0', // 当前显示的歌词
      isMuted: false, // 是否经验 默认不静音
      volume: 100, // 音频音量
      likeList: [],
      playType: 0 // 播放类型 0代表播放单曲 1代表播放歌曲列表
    }
  },
  computed: {
  },
  created () {
    this.playingSong = this.$store.state.songPlayList[JSON.parse(localStorage.curSongPlayIndex)]
    this.playType = this.$store.state.songPlayList.length === 1 ? 0 : 1
    console.log(localStorage.routeBeforePlay)
    this.showGoBack.path = (localStorage.routeBeforePlay)
    this.getLikeList()
    this.loadMusic()
  },
  mounted () {
    this.autoPlaySong()
  },
  watch: {
  },
  methods: {
    getLyrics () { // 显示歌词
      // 请求歌词
      this.$axios.get(`/lyric?id=${this.playingSong.id}`).then(res => {
        if (res.code === 200) {
          if (res.needDesc) { // 当前歌曲没有歌词
            this.lyricsObjArr = [
              { time: 0, lyric: '纯音乐,请欣赏!', uid: 666666 },
              { time: 0, lyric: '我好喜欢你!!!', uid: 520520 }
            ]
          } else {
            const lyrics = {}
            lyrics.lyric = res.lrc.lyric
            lyrics.tlyric = res.tlyric.lyric
            this.lyrics = lyrics
            // 解析歌词
            this.analysisLyrics(this.lyrics)
          }
        }
      })
    },
    getMusicUrl () { // 获取音乐url
      this.$axios.get(`/song/url?id=${this.playingSong.id}`).then(res => {
        if (res.code === 200) {
          if (res.data[0].url === null) {
            this.$message.warning('没有当前歌曲资源,3s后将自动播放下一首歌曲')
            setTimeout(() => {
              this.nextSong()
            }, 3000)
            return
          }
          this.musicUrl = res.data[0].url
        }
      })
    },
    getLikeStatus () { // 获取当前歌曲的喜欢状态
      this.likeList.indexOf(this.playingSong.id) !== -1 ? this.like = true : this.like = false
    },
    getMusicComment (currentPage, limit = 20) {
      let offset
      let url
      if (currentPage > 1) {
        offset = (currentPage - 1) * 20
        url = `/comment/music?id=${this.playingSong.id}&limit=${limit}&offset=${offset}`
      } else {
        url = `/comment/music?id=${this.playingSong.id}&limit=${limit}`
      }
      this.$axios.get(url).then(res => {
        if (res.code === 200) {
          this.showCommentPanel.total = res.total
          this.showCommentPanel.comments = res.hotComments
            ? res.hotComments.concat(res.comments)
            : this.showCommentPanel.comments.concat(res.comments)
          console.log(this.showCommentPanel.comments)
        }
      })
    },
    loadMusic () { // 加载歌曲 - 名称 图片 播放地址
      this.showGoBack.title = `${this.playingSong.songName} - ${this.playingSong.singerName}`
      this.getMusicUrl()
      this.getLyrics()
      this.getLikeStatus()
      this.getMusicComment()
      this.showCommentPanel.show = false
    },
    playSong () { // 手动点击播放歌曲
      const audio = this.$refs.audio
      this.isPlaying = !this.isPlaying
      audio.play()
      this.$refs.cd.classList.add('rotate')
      if (this.$refs.cd.classList.contains('rotatePause')) this.$refs.cd.classList.remove('rotatePause')
    },
    autoPlaySong () { // 自动播放歌曲
      const audio = this.$refs.audio
      audio.autoplay = true
      this.isPlaying = true
      this.$refs.cd.classList.add('rotate')
      if (this.$refs.cd.classList.contains('rotatePause')) this.$refs.cd.classList.remove('rotatePause')
      this.getLikeStatus()
      this.$refs.lyricUL.style.transform = 'translateY(0px)'
    },
    nextSong () { // 播放下一首歌曲
      localStorage.curSongPlayIndex++
      if (localStorage.curSongPlayIndex > this.$store.state.songPlayList.length) localStorage.curSongPlayIndex = 0
      this.playingSong = this.$store.state.songPlayList[JSON.parse(localStorage.curSongPlayIndex)]
      this.loadMusic()
      this.autoPlaySong()
      this.$refs.lyricUL.style.transform = 'translateY(0px)'
    },
    prevSong () { // 播放上一首歌曲
      localStorage.curSongPlayIndex--
      if (localStorage.curSongPlayIndex < 0) localStorage.curSongPlayIndex = this.$store.state.songPlayList.length - 1
      this.playingSong = this.$store.state.songPlayList[JSON.parse(localStorage.curSongPlayIndex)]
      this.loadMusic()
      this.autoPlaySong()
      this.$refs.lyricUL.style.transform = 'translateY(0px)'
    },
    pauseSong () { // 暂停歌曲
      this.isPlaying = !this.isPlaying
      this.$refs.audio.pause()
      this.$refs.cd.classList.add('rotatePause')
    },
    getDuration () { // canplay时获取音频总时长
      this.duration = this.$refs.audio.duration
      this.allTime = this.formatTime(this.$refs.audio.duration)
    },
    updateTime (e) { // timeupdate时获取当前播放时间
      const { currentTime } = e.target
      this.currentTime = currentTime
      this.curTime = this.formatTime(currentTime) === 'undefined' ? '00:00' : this.formatTime(currentTime)
      this.updateProgress(currentTime, this.duration)
      // 匹配歌词
      for (let i = 0; i < this.lyricsObjArr.length; i++) {
        if (this.currentTime > (parseInt(this.lyricsObjArr[i].time))) {
          const index = this.$refs.lyric[i].dataset.index
          if (i === parseInt(index)) {
            this.lyricIndex = i
            this.$refs.lyricUL.style.transform = `translateY(${170 - (30 * (i + 1))}px)`
          }
        }
      }
    },
    formatTime (time) {
      if (time === 0) {
        this.curTime = '00:00'
        return
      }
      const mins = Math.floor(time / 60) < 10 ? `0${Math.floor(time / 60)}` : Math.floor(time / 60)
      const sec = Math.floor(time % 60) < 10 ? `0${Math.floor(time % 60)}` : Math.floor(time % 60)
      return `${mins}:${sec}`
    },
    ended () {
      this.$refs.cd.classList.remove('rotate')
      this.$refs.audio.currentTime = 0
      this.isPlaying = false
      if (this.playType === 0) {
        this.$message.warning('歌曲列表只有这一首 请返回上一级!')
        this.curTime = '00:00'
        return
      }
      if ((JSON.parse(localStorage.curSongPlayIndex) >= this.$store.state.songPlayList.length - 1) || this.$route.query.from === 'fm') {
        this.$router.push('/mine/personal_fm')
        return
      }
      this.nextSong()
      console.log('播放完毕')
    },
    updateProgress (currentTime, duration) { // 更新进度条
      const precent = `${((currentTime / duration) * 100).toFixed(5)}%`
      this.precent = precent
    },
    clickProgress (event) { // 点击进度条时 更新音频时间和进度条
      const e = event || window.event
      const position = e.clientX - e.currentTarget.offsetLeft // 当前点击的位置
      const progressWidth = this.$refs.progress.offsetWidth // 进度条总宽度
      this.$refs.audio.currentTime = ((position / progressWidth) * this.duration)
      this.updateProgress(((position / progressWidth) * this.duration), this.duration)
    },
    dotStart (e) {
      // 点击的初始位置
      this.touchInfo.startX = e.touches[0].pageX - 83
    },
    dotMove (e) {
      // 移动的距离
      let moveX = e.touches[0].pageX - 83
      // 进度条的宽度
      const progressWidth = this.$refs.progress.offsetWidth
      if (moveX >= progressWidth) moveX = progressWidth
      this.$refs.audio.currentTime = ((moveX / progressWidth) * this.duration)
      this.updateProgress(((moveX / progressWidth) * this.duration), this.duration)
    },
    dotEnd (e) {
      this.playSong()
      this.isPlaying = true
    },
    analysisLyrics (lyrics) { // 解析歌词
      const olyrics = lyrics.lyric
      this.lyricsObjArr = this.lyric2ObjArr(olyrics)
    },
    lyric2ObjArr (lyric) {
      const regNewLine = /\n/
      const regTime = /\[\d{2}:\d{2}.\d{2,3}\]/
      const lineArr = lyric.split(regNewLine) // 每行歌词的数组
      const lyricsObjArr = [] // 歌词对象数组 [{time: '', lyric: ''}]
      lineArr.forEach(item => {
        if (item === '') return
        const obj = {}
        const time = item.match(regTime)
        obj.lyric = item.split(']')[1].trim() === '' ? '' : item.split(']')[1].trim()
        obj.time = time ? this.formatLyricTime(time[0].slice(1, time[0].length - 1)) : 0
        obj.uid = Math.random().toString().slice(-6)
        if (obj.lyric === '') {
          console.log('这一行没有歌词')
        } else {
          lyricsObjArr.push(obj)
        }
      })
      return lyricsObjArr
    },
    formatLyricTime (time) { // 格式化歌词的时间 转换成 sss:ms
      const regMin = /.*:/
      const regSec = /:.*\./
      const regMs = /\./
      const min = parseInt(time.match(regMin)[0].slice(0, 2))
      let sec = parseInt(time.match(regSec)[0].slice(1, 3))
      const ms = time.slice(time.match(regMs).index + 1, time.match(regMs).index + 3)
      if (min !== 0) {
        sec += min * 60
      }
      return Number(sec + '.' + ms)
    },
    toggleLikeMusic (like = true) { // like为true表示默认点击喜欢音乐 传入false表示取消喜欢
      like ? this.like = true : this.like = false
      this.$axios.get(`/like?id=${this.playingSong.id}&like=${like}`).then(res => {
        if (res.code === 200) {
          like
            ? this.$message.success('已成功添加到喜欢的音乐')
            : this.$message.success('你抛弃了她!')
        } else {
          this.showLikeErrorMsg(like)
        }
      })
    },
    showLikeErrorMsg (likeStatus) {
      if (likeStatus) {
        this.like = false
        this.$message.error('不好意思,歌曲不喜欢你!')
      } else {
        this.like = true
        this.$message.error('不好意思,她舍不得离开你!')
      }
    },
    showComment () { // 显示评论组件
      this.showCommentPanel.show = !this.showCommentPanel.show
    },
    download () {
      const a = document.createElement('a')
      a.href = this.musicUrl
      a.download = `${this.playingSong.songName} - ${this.playingSong.singerName}`
      a.click()
    },
    muted (status) { // true 表示要调至静音 false 表示要调至最大声
      if (status) {
        this.isMuted = !this.isMuted
        this.$refs.audio.muted = !this.$refs.audio.muted
        this.volume = 0
      } else {
        this.isMuted = !this.isMuted
        this.$refs.audio.muted = !this.$refs.audio.muted
        this.volume = 100
      }
    },
    handleVolumeChange () {
      this.$refs.audio.volume = this.volume / 100
      this.volume / 100 === 0 ? this.isMuted = true : this.isMuted = false
    },
    getMoreComment (currentPage, pageSize) { // 获取更多评论
      this.getMusicComment(currentPage, pageSize)
    },
    toggleLikeComment (id, cid, cIndex) {
      const status = this.showCommentPanel.comments[cIndex].liked // true -- 表示点赞过。false -- 表示未点赞
      if (status) {
        this.$axios.get(`/comment/like?id=${id}&cid=${cid}&t=0&type=0`).then(res => {
          if (res.code === 200) {
            this.showCommentPanel.comments[cIndex].liked = !this.showCommentPanel.comments[cIndex].liked
            this.$message.warning('渣男,你就这样抛弃人家!')
          }
        })
      } else {
        this.$axios.get(`/comment/like?id=${id}&cid=${cid}&t=1&type=0`).then(res => {
          if (res.code === 200) {
            this.showCommentPanel.comments[cIndex].liked = !this.showCommentPanel.comments[cIndex].liked
            this.$message.success('人家超喜欢你的,说话又好听')
          }
        })
      }
    },
    getLikeList () { // 获取喜欢的音乐的ID列表
      this.$axios.get(`/likelist?uid=${JSON.parse(localStorage.uid)}`).then(res => {
        if (res.code === 200) {
          this.likeList = res.ids
        }
      })
    }
  },
  components: {
    goBack,
    comment
  },
  beforeRouteEnter (to, from, next) {
    document.body.scrollTop = 0
    document.documentElement.scrollTop = 0
    next()
  },
  beforeRouteLeave (to, from, next) {
    if (this.isPlaying) { // 播放状态 false为暂停 true为播放
      this.pauseSong()
      setTimeout(() => {
        next()
      }, 20)
    } else {
      next()
    }
  }
}
</script>

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359

以上就实现了所有功能啦

感谢你的耐心观看 点个赞吧!再收个藏吧!

 


滴石it网-Java学习中高级和架构师教程_Java企业级开发项目实战下载 » 使用vue实现自己音乐播放器仿网易云 移动端 (audio、播放、暂停、上一首、下一首、展示评论、音量控制、进度条拖拽)

常见问题FAQ

发表回复

开通VIP 享更多特权,建议使用QQ登录