一,首先介绍一下h5原生播放器的属性和事件。
属性(这里只介绍本文使用到的属性和常用属性):
autoplay 是否自动播放
controls 是否隐藏控制面板
currentTime 当前播放进度以秒为单位
duration 进度条总长度
loop 是否循环播放
muted 是否静音
preload 资源加载方式 ; none表示不进行预加载,metadata表示不进行预加载但会获取进度长度,auto表示对资源进行预加载
src 资源加载路径
事件(这里只介绍本文使用到的事件和常用事件):
| 事件名称 | 触发时机 |
|---|---|
| ended | 播放到媒体的结束位置,播放停止。 |
| loadeddata | 媒体的第一帧加载完成。 |
| loadedmetadata | 元数据加载完成。 |
| pause | 播放暂停。 |
| play | 播放开始。 |
| playing | 因为缺少数据而暂停或延迟的状态结束,播放准备开始。 |
| ratechange | 播放速度变化。 |
| timeupdate | 由 currentTime 指定的时间更新。 |
| volumechange | 音量变化。 |
| waiting | 因为暂时性缺少数据,播放暂停。 |
二,实现思路讲解
场景:客户需要一个可以变更样式的简单音乐播放控件。进度条可拖拽,可暂停播放,可调整音量。(没有一键静音😂,感觉不是很难可以自己加)
解决方案:使用h5原生播放器<audio>原生功能并隐藏原生控制面板,通过html标签重构外观实现。
实现效果:如下

三,使用到的技术方案展示
js/html/scss/vue2/elementui
选型思路,首先三件套是基础,vue2主要是因为公司的项目比较老旧,所以没有选择最新的vue3框架,后期会考虑往vue3迁徙。最后用到elemtui。主要是因为手写一个进度条太浪费时间,而且实现进度条的技术难度很低,自己实现一个进度条可以说是既浪费时间又没有什么提升。所以进度条方案选择了elementui组件。
直接上完整源码
<template>
<div class="audioPlayer" v-show="visible">
<div class="audioTitle">
{{ title }}
</div>
<div class="btn">
<i
@click="playandstop"
:class="!isplay ? 'el-icon-video-play' : 'el-icon-video-pause'"
></i>
</div>
<div class="progressBox">
<div style="margin-right: 20px">{{ start }}</div>
<el-slider
v-model.lazy="sliderValue"
style="width: 400px"
@input="clickSilder"
@change="clickSilder"
:show-tooltip="false"
:max="maxTime"
:step="0.1"
></el-slider>
<div style="margin-left: 15px">{{ end }}</div>
<div>
<div class="volumeBox">
<div class="volumeSlider">
<span>{{ volumeValue }}</span>
<el-slider
v-model="volumeValue"
vertical
height="100px"
@change="volumeSilder"
:max="maxVolume"
:min="0"
:show-tooltip="false"
>
</el-slider>
</div>
<div class="imgWaper">
<img src="@/assets/images/workSquare/volumeBlock.png" alt="" />
</div>
</div>
</div>
</div>
<div class="close" v-if="showCloseBtn">
<i class="el-icon-close" @click="$emit('update:visible', false)"></i>
</div>
<audio
@volumechange="volumeChange"
@ended="playEnded"
@loadedmetadata="loadedmetadata"
style="display: none"
id="audioPlayer"
:src="audioUrl"
preload="auto"
:autoplay="autoplay"
></audio>
</div>
</template>
<script>
export default {
props: {
visible: {
type: Boolean,
default: true
},
audioUrl: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
showCloseBtn: {
type: Boolean,
default: false
},
autoplay: {
type: Boolean,
default: false
}
},
data() {
return {
isplay: false,
start: '0:00', //初始值
end: '0:00', //初始值
audio: null, //audio元素
sliderValue: 0,
maxTime: 100,
inThrottle: undefined,
volumeValue: 100,
maxVolume: 100
}
},
mounted() {
this.audio = document.querySelector('#audioPlayer')
this.audio.addEventListener('timeupdate', this.domDone)
},
methods: {
formate(time) {
const minutes = Math.floor(time / 60)
const remainingSeconds = Math.floor(time % 60)
// 确保秒数是两位数
const displaySeconds =
remainingSeconds < 10 ? '0' + remainingSeconds : remainingSeconds
return minutes + ':' + displaySeconds
},
domDone(event) {
this.$nextTick(() => {
this.start = this.formate(event.target.currentTime)
this.end = event.target.duration
? this.formate(event.target.duration)
: ''
this.sliderValue = Math.floor(event.target.currentTime * 10) / 10
this.maxTime = Math.floor(event.target.duration * 10) / 10
})
},
playandstop() {
if (this.audio.paused) {
this.audio.play()
this.isplay = true
} else {
this.audio.pause()
this.isplay = false
}
},
volumeChange() {
this.volumeValue = Math.round(this.audio.volume * 100)
},
clickSilder(val) {
// 优化拖动silder卡顿
if (!this.inThrottle) {
this.inThrottle = true
setTimeout(() => {
this.inThrottle = false
}, 50)
} else {
this.audio.currentTime = val
return
}
},
playEnded() {
this.$emit('playEnded')
},
play() {
this.$nextTick(() => {
this.audio.play()
})
},
pause() {
this.$nextTick(() => {
this.audio.pause()
})
},
reset() {
// 重置播放器的状态
this.audio.currentTime = 0
this.audio.volume = 1
this.volumeValue = 100
this.isplay = false
this.audio.pause()
},
loadedmetadata(event) {
this.start = this.formate(event.target.currentTime)
this.end = this.formate(event.target.duration)
},
volumeSilder(val) {
this.audio.volume = val / 100
}
}
}
</script>
<style scoped lang="scss">
.audioPlayer {
// 定位
// position: fixed;
display: flex;
justify-content: center;
align-items: center;
// bottom: 0px;
// left: 0px;
width: 100%;
height: 50px;
z-index: 999;
background: rgba(255, 255, 255, 0.425);
backdrop-filter: blur(10px);
border-radius: 5px;
}
.audioTitle {
margin-right: 10px;
}
.progressBox {
display: flex;
align-items: center;
}
.btn {
display: flex;
align-items: center;
cursor: pointer;
i {
scale: 1.5;
margin-right: 10px;
display: flex;
align-items: center;
color: rgb(29, 29, 29);
}
}
.close {
position: absolute;
top: 5px;
right: 5px;
cursor: pointer;
}
.volumeBox {
position: relative;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
height: 50px;
.volumeSlider {
position: absolute;
left: 0px;
top: -118px;
padding-bottom: 10px;
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.911);
backdrop-filter: blur(10px);
border-radius: 5px;
> span {
display: flex;
width: 100%;
justify-content: center;
margin-bottom: 10px;
color: #000000;
}
::v-deep .el-slider__button {
width: 7px;
height: 7px;
}
::v-deep .el-slider.is-vertical .el-slider__runway {
width: 5px;
}
.imgWaper {
height: 100%;
}
}
img {
height: 20px;
width: 20px;
margin-left: 8px;
margin-top: 5px;
}
}
.volumeBox:hover {
.volumeSlider {
display: flex !important;
}
}
::v-deep .el-slider__button {
width: 10px;
height: 10px;
}
</style>
这个音乐播放器是基于简单需求进行开发的,后期应该不会再升级更复杂的功能,此播放器的开发被我暂停在了1.0初级版本。
如果各位需要更复杂的功能和需求可以再此基础上进行升级开发,可拓展的空间很大。
如果点击量不错,后续还会更新
h5原生视频播放器自定义播放器外观
敬请期待
8337

被折叠的 条评论
为什么被折叠?



