需求:封装一个音乐播放器组件,并在同一个页面多次引入,播放其中一个时其它暂停播放,效果图如下:
11.播放器的代码可以直接参考Vue 实现音乐播放器,上图样式是稍微改了下的,看的更顺眼点。
2.为了解决点击一个播放其它暂停(指的是按钮变回暂停),目前做法是通过父页面的数据设置一个isPlay
进行控制,当组件播放状态进行变化时,修改数据的isPlay
达到修改组件按钮状态的目的。
3.遇到的另一个问题是,滑块拖动进度条问题,滑块拖动成功,但是进度设置无效。解决方法可以看这里vue实现audio进度拖拽播放及拖拽播放问题解决
原因:
2解决方式:
3对应本文的代码就是:
45
完整代码
父页面引用
<template>
<div style="margin-top: 10px" v-for="(item, index) in list" :key="index">
音乐{{ index }}
<audioPlayer
:audioSrc="item.src"
:id="index"
:isPlay="item.isPlay"
@changSatus="changSatus"
/>
</div>
</template>
<script>
import audioPlayer from '@/components/audioPlayer/index'
export default {
components: {
audioPlayer,
},
data() {
return {
list: [
{
src: 'xxx', // 音频路径
isPlay: false, // 播放状态
},
{
src: 'xxx',
isPlay: false,
},
{
src: 'xxx',
isPlay: false,
},
],
}
},
methods: {
// 子组件传回当前点击的播放器状态,其它音频的播放状态全部设置为暂停
changSatus(index, status) {
this.list.forEach((item, i) => {
if (i === index) {
this.$set(this.list[index], 'isPlay', status)
} else {
this.$set(this.list[i], 'isPlay', false)
}
})
},
},
}
</script>
组件页
<template>
<div class="audio-player-box">
<el-row :gutter="10">
<el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="3">
<div class="play-btn-box">
<i
class="play-btn"
:class="isPlay ? 'el-icon-video-pause' : 'el-icon-video-play'"
@click="musicPlay()"
></i>
</div>
</el-col>
<el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="16">
<div
class="slider-box"
@mousedown="isDraging = true"
@mouseup="isDraging = false"
>
<el-slider
v-model="sliderVal"
:format-tooltip="formatTooltip"
:min="sliderMin"
:max="sliderMax"
@change="spliderSelect"
/>
</div>
</el-col>
<el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="5">
{{ currentTime }} / {{ duration }}
</el-col>
</el-row>
<audio
:ref="`singeBox_${id}`"
class="audio"
controls
:src="src"
style="display: none"
>
<source src="horse.mp3" type="audio/mpeg" />
您的浏览器不支持 audio 元素。
</audio>
</div>
</template>
<script>
export default {
name: 'AudioPlayer',
props: {
audioSrc: {
// 音频路径
type: String,
default: '',
},
id: {
// 标识
type: Number,
default: 1,
},
isPlay: {
// 是否正在播放
type: Boolean,
default: false,
},
},
watch: {
isPlay(newV, oldV) {
this.play = newV ? true : false
},
},
data() {
return {
box: {}, // audio对象
src: '', // 播放地址
duration: '00:00', // 音乐总时长
currentTime: '00:00', // 当前播放时长
sliderVal: 0, // 这个对接当前时长。
sliderMin: 0,
sliderMax: 0, // 这个对接总时长。
index: 0, // 当前播放的音乐素质索引
play: false, // 播放状态,true为正在播放
isDraging: false, // 设置拖动修改的时机
}
},
mounted() {
const _this = this
this.src = this.audioSrc
this.$nextTick(() => {
_this.init()
})
},
methods: {
init() {
const _that = this
this.box = this.$refs['singeBox_' + this.id]
// 绑定三个触发方法
// 当时长有变化时触发,由"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('加载出错!')
}
},
updateTime() {
if (!this.isDraging) {
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.sliderMax = this.box.duration
// 值为xx.xxxxx 需要取整
this.sliderVal = Math.floor(this.box.currentTime)
}
},
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'),
}
},
formatTooltip(val) {
// 格式化毫秒数,由于组件提示为纯数字,所以这里需要将数字转化为我们所需要的的格式,string类型的。'03:45',
const time = this.formatTime(val)
return `${time.min}:${time.sec}`
},
spliderSelect() {
// 滑块松动后触发。更新当前时长,
// 时长发生变动会init里的方法进行更新数据
this.box.currentTime = this.sliderVal
},
musicPlay() {
this.play = !this.play
if (this.play) {
const audios = document.getElementsByTagName('audio')
;[].forEach.call(audios, function (i, index) {
if (i !== audioDom) {
i.pause()
// i.currentTime = 0
}
})
let audioDom = this.$refs['singeBox_' + this.id]
audioDom.play()
this.$emit('changSatus', this.id, true)
} else {
this.box.pause()
this.$emit('changSatus', this.id, false)
}
},
},
}
</script>
<style lang="scss" scope>
.audio-player-box {
width: 500px;
height: 50px;
line-height: 50px;
border: 1px solid #ccc;
.play-btn-box {
text-align: center;
.play-btn {
display: inline-block;
width: 20px;
height: 20px;
font-size: 30px;
cursor: pointer;
color: #409eff;
line-height: 50px;
}
}
.slider-box {
position: relative;
top: 6px;
}
}
</style>
如果有更好的实现方式,欢迎留言探讨。
网友评论