前端h5录音

时隔差不多半个月, 现在才来写这编博客。由于某些原因,我一直没有写,请大家原谅。前段时间开发了一个小模块。模块的主要功能就是有一个录音的功能。也就是说,模仿微信发送语音的功能一样。不多说,直接来一段代码

//自定义长按事件,注意, directives是跟 data ,created() 同一级的,注意注意
directives: {
    longpress: {
        bind(el, binding, vnode) {
            let pressTimer = null;
            let maxPressTime = 60000; // 60秒 = 60000毫秒  
            let startCallback = binding.value.start || Vue.noop;
            let endCallback = binding.value.end || Vue.noop;

            function handlePress() {
                startCallback();
                pressTimer = setTimeout(() => {
                    endCallback();
                    clearTimeout(pressTimer);
                    pressTimer = null;
                }, maxPressTime);
            }

            function handleRelease() {
                if (pressTimer) {
                    clearTimeout(pressTimer);
                    pressTimer = null;
                    endCallback();
                }
            }

            // 确保这些函数在unbind中可用  
            el._handlePress = handlePress;
            el._handleRelease = handleRelease;

            // 添加事件监听器  
            el.addEventListener('mousedown', handlePress);
            el.addEventListener('touchstart', handlePress);
            el.addEventListener('mouseup', handleRelease);
            el.addEventListener('touchend', handleRelease);
            el.addEventListener('mouseleave', handleRelease);
            el.addEventListener('touchcancel', handleRelease);
        },
        unbind(el) {
            // 移除事件监听器  
            el.removeEventListener('mousedown', el._handlePress);
            el.removeEventListener('touchstart', el._handlePress);
            el.removeEventListener('mouseup', el._handleRelease);
            el.removeEventListener('touchend', el._handleRelease);
            el.removeEventListener('mouseleave', el._handleRelease);
            el.removeEventListener('touchcancel', el._handleRelease);

            // 清理自定义属性  
            el._handlePress = null;
            el._handleRelease = null;
        }
    }
},
data(){
    return {
    	zheZhao:false,//录音时的遮罩层
    	isMai:false,//初始化,是否支持录音
        luYinAttr: {
            isAn:false,
            s: 0,
            timer:null,
            audioArray:[],
            startTime: null,//录音开始时间
            endTime: null, //录音结束时间
            mediaRecorder: null,
            recording: false, //录音状态(用于录音记时)
            timeLength: 0,//录音时长
            recordedChunks: [],
            timer: null,
            longPressThreshold:800,
        },
    }
}
//初始化录音对象(记住,录音一定得在 https里面。当然,在本地开发 localhost 可以不需要,但上线一定得在https里面)
luYin() {
	//这儿先做判断,判断当前设备或当前网络是否支持录音,如果不支持,那下面的也就不用多说了。
    //console.log(navigator, 'navigator.mediaDevices')
    if (!('mediaDevices' in navigator)) {
        this.isMai = false;
        return false;
    }
    navigator.mediaDevices.getUserMedia({ audio: true })
        .then(this.luYinSuccess) //支持录音,继续执行下面的操作
        .catch(this.luYinErr) //不支持录音,没下文
},
luYinSuccess(stream) {
    const audioContext = new AudioContext();
    //const sourceNode = audioContext.createMediaStreamSource(stream); //没用上,先注释
    const mediaRecorder = new MediaRecorder(stream);
    const recordedChunks = [];
    this.luYinAttr.mediaRecorder = mediaRecorder
    this.luYinAttr.recordedChunks = recordedChunks
    this.isMai = true;
},
luYinErr(err) {
    this.isMai = false;
    //console.log('The following error occurred: ' + err);
},



//startRecording ,  stopRecording是开始计时和结束计时(由于录音的时间不能太长,这儿我,限制为1分分钟的时长。所以,我得有一个录音计时,超过1分钟,录音取消)
//开始计时
startRecording() {
    console.log('开始计时')
    this.luYinAttr.isAn = true;
    this.zheZhao = true;
    this.luYinAttr.s = 0;
    this.luYinAttr.recording = true;
    this.luYinAttr.startTime = Date.now();
    this.luYinAttr.timer = setInterval(() => {
        this.luYinAttr.s = this.luYinAttr.s + 1;
    } , 500)
},
//结束录音计时
stopRecording() {
    this.luYinAttr.recording = false;
    const endTime = Date.now();
    const startTime = this.luYinAttr.startTime
    const recordDuration = (endTime - startTime) / 1000; // 计算录音时长(秒) 
    if (recordDuration >= 60) {
        this.luYinAttr.timeLength = 60;
        //结束录音
    }
    this.luYinAttr.timeLength = recordDuration;
    /*const maxWidth = 300; // 设置图标的最大宽度  
    const indicatorWidth = Math.min(recordDuration * 20, maxWidth); // 根据录音时长计算图标宽度,假设每秒对应2个像素宽度  
    console.log(indicatorWidth, '时长')
    console.log('结束计时')*/
},



startLongPress() {
    //console.log('长按开始');
    let that = this;
    clearTimeout(this.luYinAttr.timer);
    that.luYinAttr.timer = setTimeout(function () {
        // 执行长按操作  
        //console.log('长按操作开始');
        that.luYinAttr.mediaRecorder.start();
        //console.log(that.luYinAttr.mediaRecorder.state , 'qqggg');
        //startRecord.disabled = true;
        //stopRecord.disabled = false;
        that.startRecording();
    }, that.luYinAttr.longPressThreshold);
    // 在这里编写长按开始时的逻辑
},
endLongPress() {
    //长按结束事件
    let that = this;
    //console.log('取消')
    clearTimeout(that.luYinAttr.timer);
    that.luYinAttr.mediaRecorder.stop();
    that.stopRecording();
    that.luYinAttr.mediaRecorder.ondataavailable = async function (e) {
        console.log(e)
        if (e.data.size > 0) {
            const blobObj = e.data;
            let nowTime = new Date().getTime();
            let fileName = 'LY_' + nowTime + '.mp3';
            const file = new File([blobObj], fileName, { type: 'audio/mpeg' });
            //that.uplodAudio(file) //上传录音
            that.luYinAttr.isAn = false;
            that.zheZhao = false;
            clearInterval(that.luYinAttr.timer)
        } else {
            // no data to push  
        }
    };
},


//试听录音(在苹果机上不支持)
listenAudio(obj, index) {
    let myTimer = null;
    this.play.listenStatus = this.play.listenStatus + 1;
    if (this.play.listenStatus > 1) {
        clearInterval(myTimer)
        return false;
    }

    if (!this.playActive.isLongPressing) {
        
        let that = this;
        let itemAudio = [(that.luYinAttr.recordedChunks)[index]]
        //console.log(itemAudio, 'itemAudio', obj)
        let len = JSON.parse(JSON.stringify(obj.timeLength));
        obj.timeLength = 0;
        myTimer = setInterval(() => {
            obj.timeLength = obj.timeLength + 1;
            if (obj.timeLength == len) {
                clearInterval(myTimer)
                this.play.listenStatus = 0;
            }
        } , 1000)

        const blob = new Blob(itemAudio, { 'type': 'audio/ogg; codecs=opus' });
        //const blob = new Blob(that.luYinAttr.recordedChunks, { 'type': 'audio/ogg; codecs=opus' });
        //console.log(blob, 'blob')
        const audioURL = window.URL.createObjectURL(blob);
        //console.log(audioURL, 'audioURL')
        const audio = new Audio(audioURL);
        //console.log(audio,'audio')
        audio.play().catch(err => {
            console.log('Failed to play sound:', err);
        });
    }
},




<template v-if="isMai == true">
    <div class="" style="background:#ffffff; padding:10px 16px;">
        <div class="list" style="text-align:center">
            <template v-for="(audioArrayItem , audioArrayIndex) in luYinAttr.audioArray">
                <el-tooltip placement="top" :manual="true" :value="audioArrayItem.tooltip">
                    <div slot="content">
                        <span @click="returnAudioArrayItem(audioArrayItem , audioArrayIndex)">移除</span>
                    </div>
                    <div style="margin-bottom:10px;"  @click.prevent="listenAudio(audioArrayItem , audioArrayIndex)">
                        <div style="overflow:hidden">
                            <div style="float:left">
                                <p style="background: #3975C6; color: #ffffff; padding:0 8px; display:inline-block; border-radius:4px;">
                                    <span class="icon iconfont playIcon" style="display:inline-block; height:20px; font-size:14px; text-align:center;">&#xe618;</span>
                                    <span style="position:relative; top:-5px; margin:0 5px;">
                                        <template v-for="(item , index) in audioArrayItem.timeLength">
                                            <span>,,</span>
                                        </template>
                                    </span>
                                    <span>{{ audioArrayItem.timeLength }}'</span>
                                </p>
                            </div>
                            <div style="float:right"><van-button type="info" size="mini" @click.stop="returnAudioArrayItem(audioArrayItem , audioArrayIndex)">移除</van-button></div>
                        </div>
                    </div>
                </el-tooltip>
            </template>
        
        </div>
        <div class="byBtn" :class="luYinAttr.isAn == true ? 'myIsYesAn': 'myIsNoAn' " style="text-align: center; font-size:14px;" v-longpress="{ start: startLongPress, end: endLongPress }">
            <p class="icon iconfont" style="color: #3975C6; font-size: 24px;">&#xe7a6;</p>
            <p>任务详情 - 按住说话</p>
        </div>
    </div>
</template>
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值