前言
公司使用了钉钉录音功能,音频格式为amr,通过寻找找到了一下库,配合库整理后写了下面这个组件。
前置资源
- 调用的库 AMR 录音机
npm install benz-amr-recorder var BenzAMRRecorder = require('benz-amr-recorder'); // 详细教程请参考下方链接 // https://github.com/BenzLeung/benz-amr-recorder
源码
<template>
<div class="amr-container">
<div class="amr-content">
<div class="play" @click="play" v-if='!pause'></div>
<div class="pause" @click="stop" v-if='pause'></div>
<div class="process" ref="pgs" @click="handlerAudioPass($event)">
<div class="pgs-play" ref="pgsPlay"></div>
<div class="circle" ref="circle"
@touchstart="passStart"
@touchmove="passMove($event)"
@touchend="passEnd">
</div>
</div>
<div class="duration">{{this.currentTime | formatTime}}/{{ this.time | filterTime}}</div>
</div>
</div>
</template>
<script>
/**
* 播放amr音频组件,全局定义amr变量,在mounted做初始化设置
*/
var BenzAMRRecorder = require('benz-amr-recorder');
var amr =''
export default {
name: 'playAmr',
props:['urls','clear','text'],
data(){
return{
pause: false,
isShowAudioWord: false,
currentTime: 0, // 当前播放时长
time: 0, // 总时长
totalWidth: 0, // 播放器进度条长度
timer: '', // 进度条的计时器
}
},
filters:{
// 处理音频总长度,只处理了2分钟以内的音频长度,如有需要,请修改
filterTime: function(val){
let intTime = 0;
if(val>60){
let zero = Math.round(val-60)<10? '0'+Math.round(val-60) : Math.round(val-60)
intTime = ' 1:' + zero
}else{
let zero = Math.round(val)<10? '0'+Math.round(val) : Math.round(val)
intTime = ' 0:' + zero
}
return intTime
},
//格式化音频的当前播放位置的秒数,根据进度条的变化而变化
formatTime: function(val){
let time = val.toFixed(0);
let len = parseInt(time / 60);
let second = time - len*60
// console.log(time,len,second)
if(second<10) second = '0'+second
// console.log(len+':'+second)
return len+':'+second+' '
}
},
methods:{
// 初始化音频
init(){
this.totalWidth = this.$refs.pgs.offsetWidth;
let url = 'https://benzleung.github.io/benz-amr-recorder/res/mario.amr' // 音频url,可以通过调用组件时传入,这里偷懒了给了默认值
let _self = this;
amr = new BenzAMRRecorder();
amr.initWithUrl(url).then(function() {
_self.time = amr.getDuration(); // 初始化音频,获取音频总长度
//console.log(_self.time)
})
},
// 播放音频
play(){
let _self = this;
amr.play(this.currentTime); // 按当前的音频位置开始播放
this.pause = true
amr.onEnded(function() {
//自动完成播放
_self.pause = false;
})
this.updateProgress();
},
// 更新进度条
updateProgress() {
// var value = Math.round((this.audio.currentTime / this.audio.duration) * 100, 0);
this.timer = setInterval(()=>{
let currentTime = amr.getCurrentPosition(); // 获取播放的音频的位置,小数位很长一串数
this.currentTime = currentTime
if(currentTime > this.time - 0.02){ // 音频播放完成,恢复到初始设置,计时器10ms一次,播放完成的位置可能达不到视频的长度位置差距极小
clearInterval(this.timer)
this.$refs.pgsPlay.style.width = '0%'
this.$refs.circle.style.left = '0%'
}else{
var value = Math.round((currentTime / this.time) * 100, 0);
this.$refs.pgsPlay.style.width = value + '%'
this.$refs.circle.style.left = value + '%'
}
},10)
},
// 更新进度条样式
updateProgressStyle(currentTime){
var value = Math.round((currentTime / this.time) * 100, 0);
this.$refs.pgsPlay.style.width = value + '%'
this.$refs.circle.style.left = value + '%'
},
// 暂停播放音频,清空更新进度条的计时器
stop(){
amr.pause() // 暂停播放音频
this.pause = false;
clearInterval(this.timer)
},
// 开始拖动进度条时,停止播放音频
passStart() {
this.stop()
},
// 结束拖动进度条时,开始播放音频
passEnd() {
this.play()
},
// 移动进度条时
passMove(e) {
// console.log(this.audio.duration)
e.preventDefault();
var startX = this.$refs.pgs.getBoundingClientRect().left; // 进度条开始的x坐标
var endX = e.targetTouches[0].clientX; // 点击事件的x坐标
// console.log(this.$refs.pgs,endX)
let rate = 0
if ((endX + 1) > startX && endX < (startX + this.totalWidth)) { // 触摸范围大于进度条起点,小于进度条终点
this.$refs.circle.style.left = (endX - startX - 1) + "px"
rate = (endX - startX) / this.totalWidth;
this.currentTime = rate * this.time;
this.updateProgressStyle(this.currentTime);
}
},
// 手动点击选择进度条播放位置,先暂停播放,选中位置后,继续播放
handlerAudioPass(e) {
this.passStart()
let rate = 0
var startX = e.target.getBoundingClientRect().left; // 进度条开始的x坐标
var endX = e.clientX; //点击事件的x坐标
// console.log(startX,endX)
rate = (endX - startX) / this.totalWidth;
this.$refs.circle.style.left = (endX - startX - 1) + "px"
this.currentTime = rate * this.time;
this.updateProgressStyle(this.currentTime);
setTimeout(()=>{
this.passEnd();
},10)
},
},
mounted(){
this.init(); //初始化音频
},
}
</script>
<style scoped>
.amr-container{
position: relative;
height: 50px;
width: 90%;
margin: 0 auto;
background: #D9EDFF;
border-radius: 30px;
}
.amr-content{
display: flex;
position: relative;
}
.play{
position: absolute;
top: 15px;
left: 24px;
border-style: solid;
border-width: 10px 0px 10px 16px;
border-color: transparent transparent transparent black;
}
.pause{
width: 10px;
height: 16px;
border-style: double;
border-width: 0px 0px 0px 16px;
border-color: #202020;
position: absolute;
top: 17px;
left: 24px;
}
.process{
height: 6px;
width: 48%;
background: #BADAF9;
position: absolute;
left: 58px;
top: 22px;
border-radius: 20px;
}
.pgs-play {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 100%;
background-color:#168DFF;
z-index: 1;
border-radius: 20px 0 0 20px;
}
.circle {
position: absolute;
top: -3px;
left: -6px;
width: 12px;
height: 12px;
border-radius: 50%;
background-color:#168DFF;
}
.duration{
position: absolute;
right: 24px;
height: 20px;
top: 15px;
color: #168dff;
}
</style>