前言
需求分析:
- 在web端实现音频播放,进度条随着歌曲的播放延长,歌曲播放完时长度等于浅紫色总进度条长度,时间实时更新;
- 点击进度条,紫色进度条长度变为点击处至起点的长度,并从当前点开始播放歌曲;
- 实现暂停、播放切换;当音频播放结束后,停止播放,点击播放按钮,可以从头播放;
-
左右控件实现快进快退功能;
<template>
<div class="player">
<div class="img-gif"></div>
<!-- 进度条 -->
<div class="progress-wrapper">
<!-- 时间显示 -->
<span class="time">{{currentDuration}}|{{duration}}</span>
<div class="progress-bar-wrapper">
<div class="progress-bar" ref="progressBar" @click="progressClick">
<div class="bar-inner">
<div class="progress" ref="progress"></div>
<div class="progress-btn-wrapper" ref="progressBtn">
<div class="progress-btn"></div>
</div>
</div>
</div>
</div>
</div>
<!-- 操作按钮 -->
<div class="operators">
<img :src="require('@/assets/voice/back.png')" @click="fastBack" class="i-left"/>
<img :src="playImage" @click="changeStatus" class="i-left"/>
<img :src="require('@/assets/voice/prev.png')" @click="forward" class="i-left"/>
</div>
<audio
controls
id="maudio"
ref="maudio"
preload="auto"
autoplay
style="display:none;"
@timeupdate="onTimeupdate"
@ended="audioEnd"
>
<source :src="audioURL" ref="msource" type="audio/wav" />您的浏览器不支持音频播放
</audio>
</div>
</template>
scss部分
.player {
position: relative;
top: 0;
right: 0;
left: 0;
bottom: 0;
// background: #eee;
.img-gif {
width: 420px;
height: 70px;
border: 3px solid rgba(238, 230, 255, 1);
border-radius: 40px 40px 4px 40px;
background: url("../../../../assets/common/audio-gif.gif") no-repeat center;
margin: 0px auto;
}
.progress-wrapper {
display: flex;
align-items: center;
width: 95%;
margin: 0px auto;
padding: 10px 0;
.progress-bar-wrapper {
flex: 1;
margin-right: 5px;
.progress-bar {
height: 30px;
cursor: pointer;
.bar-inner {
position: relative;
top: 13px;
height: 4px;
background: rgba(238,229,255,1);
.progress {
position: absolute;
height: 100%;
background-color: #bc99ff;
}
.progress-btn-wrapper {
position: absolute;
left: -8px;
top: -13px;
width: 30px;
height: 30px;
.progress-btn {
position: relative;
top: 7px;
left: 7px;
box-sizing: border-box;
width: 16px;
height: 16px;
border: 3px solid #fff;
border-radius: 50%;
background: #bc99ff;
}
}
}
}
}
.time {
color: rgba(238, 229, 255, 1);
font-size: 12px;
width: 110px;
text-align: left;
}
}
.operators {
cursor: pointer;
text-align: center;
img{
vertical-align: middle;
margin: 0 20px;
}
}
}
逻辑部分
<script>
import { showNum } from "@/utils/common.js";
export default {
props: {
audioURL: {
type: String,
default() {
return "";
}
},
duration: {
type: String,
default() {
return "00:00:00";
}
},
/* 总时长秒数 */
second: {
type: Number,
default() {
return 0;
}
}
},
data() {
return {
currentTime: 0,
currentDuration: "00:00:00",
percent: 0,
playing: true
};
},
created() {
this.touch = {};
},
methods: {
//播放时间
onTimeupdate(e) {
this.currentTime = parseInt(e.target.currentTime);
},
//后退
fastBack() {
this.currentTime--;
this.$refs.maudio.currentTime = this.currentTime;
},
//改变播放状态
changeStatus() {
if (this.playing) {
this.$refs.maudio.pause();
} else {
this.$refs.maudio.play();
}
this.playing = !this.playing;
},
//快进
forward() {
this.currentTime++;
this.$refs.maudio.currentTime = this.currentTime;
},
//处理
handle(val) {
//毫秒数转为时分秒
let s = showNum(val % 60);
let m = showNum(parseInt(val / 60) % 60);
let h = showNum(parseInt(val / 60 / 60));
this.currentDuration = h + ":" + m + ":" + s;
this.percent = val / this.second;
},
//播放结束 修改播放状态
audioEnd() {
this.playing = false;
},
//点击进度条
progressClick(e) {
const rect = this.$refs.progressBar.getBoundingClientRect();
const offsetWidth = e.pageX - rect.left;
this.$refs.progress.style.width = offsetWidth;
this.$refs.progressBtn.style.left = offsetWidth;
this.percent = offsetWidth / rect.width;
this.$refs.maudio.currentTime = this.second * this.percent;
}
},
watch: {
//进度条变化
percent(val) {
let value = parseInt(val * 100) + "%";
this.$refs.progress.style.width = value;
this.$refs.progressBtn.style.left = parseInt(val * 100 - 5) + "%";
},
currentTime(val) {
this.handle(val);
}
},
computed: {
//播放状态
playImage() {
return this.playing ? require('@/assets/voice/play.png') : require('@/assets/voice/stop.png');
}
}
};
</script>