Vue 实现音乐播放器

好久没有听音乐了,最近想去听,发现很多歌曾经喜欢因为版权变灰色了。于是萌生了自己写个播放器项目。让听歌不再担忧那天不能再听了。
以下是实现思路和过程。欢迎探讨~

需求

1、音乐播放暂停
2、音乐切换
3、音乐拖动跳段播放

实现

1、播放器内容初始化

#页面加入audio标签

# js部分
# data
box: undefined, # audio对象
musicPath: '******',  // mp3链接
coverPath: '******',  // 封面
musicTitle: '',  // 当前播放标题
musicImg: '',  //  当前播放封面
list: [ //数据格式
   {
    id: 1,
    name: '活该',
    url: 'HuoGai',
    cover: 'ChenYou',
    singer: '谌宥',
    time: '04:12'
  }...
]
# methods方法区加入初始化方法
init() {
  this.box = this.$refs.singeBox
  this.box.src = this.list[0].url # 歌曲链接
  // 绑定三个触发方法
  // 当时长有变化时触发,由"NaN"变为实际时长也算
  this.box.ondurationchange = function() {
    console.log('时长发生了变化')
  }
  // 当前数据可用是触发
  this.box.oncanplay = function() {
    console.log('已经可以播放了')
  }
  // 播放位置发送改变时触发。
  this.box.ontimeupdate = function() {
    console.log('播放位置发送了变动')
  }
  // 音频播放完毕
  this.box.onended = function() {
    console.log('播放完毕,谢谢收听')
  }
  // 音频播放完毕
  this.box.onerror = function() {
    console.log('加载出错!')
  }
}
// mounted 页面进入是完成初始化
mounted() {
  this.init()
},
初始化结果

2、对接audio属性

controls 属性让audio控件进行了展示。但是由于外观和内容不是我们能随心进行控制的。所以我们需要独立去一个假的播放组件,去对接audio 的相关属性。

首先,对接时间
# 页面加入

总时长:{{ duration }}

当前时长:{{ currentTime }}

# data 加入 duration: undefined, # 音乐总时长 currentTime: undefined, # 当前播放时长 # method updateTime() { // 更新时间 const total = this.formatTime(this.box.duration) const current = this.formatTime(this.box.currentTime) this.duration = `${total.min}:${total.sec}` this.currentTime = `${current.min}:${current.sec}` this.musicTitle = this.list[this.index].name + ' - ' + this.list[this.index].singer this.musicImg = this.coverPath + this.list[this.index].cover + '.jpg' }, formatTime(time) { // 格式化毫秒,返回String型分秒对象 // 有可能没获取到,为NaN if (!time) return { min: '00', sec: '00' } return { min: Math.floor(time / 60).toString().padStart(2, '0'), sec: Math.floor(time % 60).toString().padStart(2, '0') } },

初始化init()里的变动方法,加入更新方法

init() {
  this.box = this.$refs.singeBox
  this.box.src = this.list[0].url # 歌曲链接
  // 绑定三个触发方法
  // 当时长有变化时触发,由"NaN"变为实际时长也算
  this.box.ondurationchange = function() {
    console.log('时长发生了变化')
    _that.updateTime()
  }
  // 当前数据可用是触发
  this.box.oncanplay = function() {
    console.log('已经可以播放了')
  }
  // 播放位置发送改变时触发。
  this.box.ontimeupdate = function() {
    console.log('播放位置发送了变动')
    _that.updateTime()
  }
  // 音频播放完毕
  this.box.onended = function() {
    console.log('播放完毕,谢谢收听')
  }
  // 音频播放完毕
  this.box.onerror = function() {
    console.log('加载出错!')
  }
},
时间数据对接完成

对接进度条

# 由于比较懒,所以暂时拿现成的进度条组件。
# script 引进 element 滑块组件
import { ElSlider } from 'element-plus'
# components 引入局部组件
components: { ElSlider }
# data 加入
sliderVal: 0, // 这个对接当前时长。
sliderMin: 0,
sliderMax: 0, // 这个对接总时长。
# 页面加入

# method
formatTooltip(val) {
  // 格式化毫秒数,由于组件提示为纯数字,所以这里需要将数字转化为我们所需要的的格式,string类型的。'03:45',
  const time = this.formatTime(val)
  return `${time.min}:${time.sec}`
},
spliderSelect() {
  // 滑块松动后触发。更新当前时长,
  // 时长发生变动会init里的方法进行更新数据
  this.box.currentTime = this.sliderVal
}

这里可以根据自己的组件进行变化。
时间更新加入进度条更新

updateTime() {
  const total = this.formatTime(this.box.duration)
  const current = this.formatTime(this.box.currentTime)
  this.duration = `${total.min}:${total.sec}`
  this.currentTime = `${current.min}:${current.sec}`
  // 值为xx.xxxxx 需要取整
  this.sliderVal = Math.floor(this.box.currentTime)
  this.musicTitle = this.list[this.index].name + ' - ' + this.list[this.index].singer
  this.musicImg = this.coverPath + this.list[this.index].cover + '.jpg'
},
进度条对接效果

实现播放暂停,上一首,下一首

# 页面加入



当前歌曲:{{ list[index].name }}
# data 加入
index: 0, # 当前播放的音乐素质索引
play: false # 播放状态,true为正在播放
# method
musicPlay(flag) {
    switch (flag) {
      case 'pre':
        if (this.list[this.index - 1]) {
          this.box.src = this.musicPath + this.list[this.index - 1].url + '.mp3'
          this.index -= 1
        } else {
          this.box.src = this.musicPath + this.list[this.list.length - 1].url + '.mp3'
          this.index = this.list.length - 1
        }
        break
      case 'play':
        this.play = !this.play
        break
      case 'next':
        if (this.list[this.index + 1]) {
          this.box.src = this.musicPath + this.list[this.index + 1].url + '.mp3'
          this.index += 1
        } else {
          this.box.src = this.musicPath + this.list[0].url + '.mp3'
          this.index = 0
        }
        break
    }
}

到此,简单的播放功能已经实现了。


简单的播放实现

优化+美化

列表播放

去掉audio标签controls属性,不显示自带的控件(功能还在,隐藏了),使用列表的播放方式

# script 引进 element 滑块组件
import { ElTable} from 'element-plus'
# components 引入局部组件
components: { ElTable}
# data
player: {} // 对象控制list谁在播放
# 页面加入表格

    
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  

# method 加入点击方法
  handlerPlay(id) {
    console.log(this.player)
    if (!this.player[id]) {
      // 没值触发新的播放
      const i = this.list.findIndex(x => x.id === id)
      this.index = i
      this.play = false
    }
    this.musicPlay('play')
  },
# musicPlay方法 重构
musicPlay(flag) {
  switch (flag) {
    case 'pre':
      if (this.list[this.index - 1]) {
        this.box.src = this.musicPath + this.list[this.index - 1].url + '.mp3'
        this.index -= 1
      } else {
        this.box.src = this.musicPath + this.list[this.list.length - 1].url + '.mp3'
        this.index = this.list.length - 1
      }
      break
    case 'play':
      this.play = !this.play
      // 对接控件 同步 列表里的控件
      if (this.player[this.list[this.index].id]) this.player[this.list[this.index].id].play = this.play
      // 新的歌曲播放
      if (this.play && !this.player[this.list[this.index].id]) this.box.src = this.musicPath + this.list[this.index].url + '.mp3'
      break
    case 'next':
      if (this.list[this.index + 1]) {
        this.box.src = this.musicPath + this.list[this.index + 1].url + '.mp3'
        this.index += 1
      } else {
        this.box.src = this.musicPath + this.list[0].url + '.mp3'
        this.index = 0
      }
      break
  }
  if (this.play && !this.player[this.list[this.index].id]) {
    this.player = {}
    this.player[this.list[this.index].id] = {}
    this.player[this.list[this.index].id].play = true
  } else {
    this.play ? this.box.play() : this.box.pause()
  }
}
  

加入对接相关的组件,绑定对应的对接参数。样式这里就忽略了。


image.png

初始化方法init加入连续播放,播放时切个继续播放,暂停时切歌保持暂停判断。

this.box.ondurationchange = function() {
        _that.play ? _that.box.play() : _that.box.pause()
        _that.updateTime()
      }
      // 当前数据可用是触发
      this.box.oncanplay = function() {
        _that.play ? _that.box.play() : _that.box.pause()
      }
      // 播放位置发送改变时触发。
      this.box.ontimeupdate = function() {
        _that.updateTime()
      }
      // 音频播放完毕
      this.box.onended = function() {
        _that.musicPlay('next')
        console.log('播放完毕,谢谢收听')
      }
      // 音频播放完毕
      this.box.onerror = function() {
        console.log('加载出错!')
      }

实现了最终结果展示:

最终效果

你可能感兴趣的:(Vue 实现音乐播放器)