前言
近期项目中经常使用到音频功能,然而自带的音频控制面板大部分情况都不能满足需
求,固用vue自定义了一个通用的的audio面板。主要功能有:播放、暂停、自定义进度
条,静音控制等内容,废话不多说,先上图
页面组成
- 播放暂停模块
- 自定义进度条模块
- 音频时长模块
- 静音控制模块
主要思路
- 使用
ref
获取audio元素 - 调用 audio
play
pause
方法实现暂停播放 - 为audio添加事件:
@canplay
@timeupdate
@ended
- 在
computed
中设置静音和非静音图片资源
html
<div class="app">
<div class="dialogDetailAudio" onselectstart="return false">
<img class="dialogAudioPlay" :src="audioImg" title="播控" @click="playAudio">
<span class="dialogAudioTime">{{time}}</span>
<div class="dialogAudioProgress" ref="dialogAudioProgress" @mousedown="controlAudioProgress($event)">
<span class="progressDot" :style="dotStyle"></span>
<span class="bar" :style="progressStyle"></span>
</div>
<span class="dialogAudioDuration">{{duration}}</span>
<img class="dialogAudioListen" :src="dialogAudioListen" title="静音" @click="listenDialogAudio">
<img class="dialogAudioDownload" src="./callRecordDownload.png" title="下载" @click="downloadCallRecord">
<audio ref="recordAudio" class="recordAudio" type="audio/mpeg"
@canplay="canPlay" @timeupdate="timeUpdate" @ended="onEnded" :src="audioUrl">
</audio>
</div>
</div>
css
* {
margin: 0;
padding: 0;
}
.dialogDetailAudio {
margin-top: 100px;
margin-left: auto;
margin-right: auto;
width: 550px;
height: 49px;
line-height: 49px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 5px 30px 0px rgba(29, 34, 54, 0.18);
border-radius: 6px;
}
.dialogAudioPlay {
display: inline-block;
position: relative;
top: 6px;
margin-left: 15px;
cursor: pointer;
width: 23px;
height: 23px;
}
.dialogAudioTime {
margin-left: 11px;
font-size: 11px;
font-weight: 400;
color: rgba(51, 51, 51, 1);
}
.dialogAudioProgress {
display: inline-block;
width: 300px;
height: 2px;
background: rgba(212, 249, 232, 1);
border-radius: 1px;
margin-left: 12px;
position: relative;
}
.progressDot {
width: 8px;
height: 8px;
border-radius: 50%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
background-color: rgba(5, 180, 147, 1);
position: absolute;
left: 0;
top: 50%;
margin-top: -5px;
margin-left: -5px;
cursor: pointer;
}
.bar {
height: 100%;
background: rgba(5, 180, 147, 1);
border-radius: 3px;
display: inline-block;
position: absolute;
}
.dialogAudioDuration {
margin-left: 11px;
font-size: 11px;
font-weight: 400;
color: rgba(34, 34, 34, 1);
}
.dialogAudioListen,
.dialogAudioDownload {
width: 16px;
height: 13px;
cursor: pointer;
}
.dialogAudioListen {
margin-left: 8px;
}
.dialogAudioDownload {
margin-left: 5px;
}
js
var app = new Vue({
el: ".app",
data() {
return {
time: "00:00",
duration: "00:00",
progressStyle: { width: "" },
dotStyle: { left: "" },
audioUrl: "http://file.duzhai.net/Files/Audio/2017-08/af01ab05-d112-4ad7-9cff-2cfecced5bc6.mp3",
audioImg: "./dialogDetailPlay.png",
dialogAudioListenGroup: ["./callRecordListen.png", "./quite.png"],
imgIndex: 0,
}
},
//计算属性 切换静音图片
computed: {
dialogAudioListen() {
return this.dialogAudioListenGroup[this.imgIndex]
}
},
methods: {
//播放暂停控制
playAudio() {
let recordAudio = this.$refs.recordAudio; //获取audio元素
if (recordAudio.paused) {
this.audioImg = "./dialogDetailPause.png"
recordAudio.play();
} else {
this.audioImg = "./dialogDetailPlay.png"
recordAudio.pause();
}
},
//进度条更新
timeUpdate() {
this.duration = this.transTime(this.$refs.recordAudio.duration);
let timeStr = parseInt(this.$refs.recordAudio.currentTime);
this.time = this.transTime(timeStr);
let scales = this.$refs.recordAudio.currentTime / this.$refs.recordAudio.duration;
this.progressStyle.width = scales * 100 + '%';
this.dotStyle.left = scales * 100 + '%';
},
//播放结束
onEnded() {
this.audioImg = "./dialogDetailPlay.png";
this.time = "00:00";
this.progressStyle.width = 0;
this.dotStyle.left = 0;
},
//用户可以开始播放audio
canPlay() {
//获取audio音频文件总时长 并设置到界面并解决出现 NAN 的问题
this.duration = this.transTime(this.$refs.recordAudio.duration);
},
//静音控制
listenDialogAudio() {
this.imgIndex = (this.imgIndex + 1) % (this.dialogAudioListenGroup).length;
if (this.dialogAudioListen == "./quite.png") {
this.$refs.recordAudio.volume = 0;
} else {
this.$refs.recordAudio.volume = 1;
}
},
//鼠标点击移动播放进度
controlAudioProgress(event) {
let audio = this.$refs.recordAudio;
let dialogAudioProgress = this.$refs.dialogAudioProgress;
if (!audio.paused || audio.currentTime != 0) {
let pgsWidth = parseFloat(window.getComputedStyle(dialogAudioProgress, null).width.replace('px', ''));
let rate = event.offsetX / pgsWidth;
audio.currentTime = audio.duration * rate;
this.timeUpdate();
}
},
//下载音频
downloadCallRecord() {
console.log("下载...");
},
//时间转换
transTime(value) {
let time = "";
let h = parseInt(value / 3600);
value %= 3600;
let m = parseInt(value / 60);
let s = parseInt(value % 60);
if (h > 0) {
time = this.formatTime(h + ":" + m + ":" + s);
} else {
time = this.formatTime(m + ":" + s);
}
return time;
},
//时间格式化
formatTime(value) {
let time = "";
let s = value.split(':');
let i = 0;
for (; i < s.length - 1; i++) {
time += s[i].length == 1 ? ("0" + s[i]) : s[i];
time += ":";
}
time += s[i].length == 1 ? ("0" + s[i]) : s[i];
return time;
}
},
})
注意点
-
onselectstart
禁止用户选中网页上的内容。
用户点击进度条位置不会选中其他内容 -
@canplay
设置audio总时长并防止出现 NAN -
@ended
视频播放完毕后应回到初始状态 -
computed
设置静音图片资源。 音频的volume
默认值是1
写到最后
其实,实现自定义内容很简单,主要就是界面与js逻辑控制的结合,只要弄清楚元素对应
的API并加以改进 就可实现很多想要的功能。希望本文可以帮到您,感谢。