h5播放amr格式的音频,仿照audio样式

1,195 阅读1分钟

前言

公司使用了钉钉录音功能,音频格式为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>