赞
踩
1、中间按钮点击录音开始,可以进行暂停,继续操作
2、录音时可以进行取消,完成操作
3、录音完成可以点击听录好的音频
4、可以将录好的音频删除重新录音
1、开始录音时需要检测是否是H5页面,H5页面没有录音功能,app端需要检测是否有录音权限
开始录音methodfile.js
export async function startRecording() { return new Promise((resolve, reject) => { try { if (!recorderManager) { recorderManager = uni.getRecorderManager(); } // 是否开启录音权限 let permission = plus.navigator.checkPermission('RECORD'); if (permission == 'authorized') { // 应用有录音权限,可以进行录音操作 recorderManager.start({ duration: profile.duration // 录音时长:3分钟 }); } else { // 应用没有录音权限,可能需要请求用户授予录音权限 // 或者显示一个提示,告知用户需要录音权限才能进行操作 reject('应用没有录音权限'); } } catch (e) { // 如果出现错误,调用 reject 函数并传递错误信息 reject('请在app和小程序端体验录音,Uni官方明确H5不支持getRecorderManager, 详情查看Uni官方文档'); } }); }
2、录音暂停清除录音计时的定时器,但是不清除秒数时长,这里需要定义一个定时器times,秒数增加num(这个在暂停清除定时器时不被清除),字符串秒数显示second
暂停录音record.vue
pauseRecording() {
let t = this
t.isStop = true
audioRecorder.pauseRecording();
clearInterval(t.times)
},
3、播放已录好的音频需要用到音频播放,详见下一个文档
4、删除录好的音频需要判断一下是否在播放,如果在播放就结束播放然后删除录好的音频
<template> <view class="page-show"> <view class="row-layout" style="justify-content: space-between;margin-top: 22rpx;" v-if="isFinish"> <view class="voice_con row-layout" @click="playVoice()"> <image class="yy_img" src="/static/image/pause.png" v-show="playing"></image> <image class="yy_img" src="/static/image/play.png" v-show="!playing"></image> <view class="voiceAniation" style="margin: 0 10rpx 0 22rpx;"> <view class="em" v-for="(item,index) in 8" :key="index" :style="playing?'':'animation: none;'"> </view> </view> <view class="time_long">{{second}}</view> </view> <image src="/static/image/delete.png" mode="widthFix" style="width: 48rpx;" @click="delVoice()"> </image> </view> <view class="page-record"> <!-- 录音背景光圈:当不处于暂停和处于录音中出现 --> <view class="bgCircle" v-show="!isStop&&isVoicing"> <!-- 外层光圈 --> <view class="bgCircleOut"> </view> <!-- 内层光圈 --> <view class="bgCircleIn"> </view> </view> <!-- 语音输入的按钮 --> <view class="voice_type" v-show="!isFinish"> <!-- 开始录音按钮 --> <view class="vertical_center" v-show="!isVoicing" @click="startRecording()"> <view class="start_record">开始记录</view> <!-- 点击开始录音:isVoicing=true正在录音状态 --> <view class="entoch_btn"> <image src="/static/image/recording.png" mode="widthFix"></image> </view> </view> <!-- 正在录音 --> <view class="vertical_center" v-show="isVoicing"> <!-- 文字写在外面是因为文字不参与垂直居中 --> <view class="start_record" v-show="!isStop"> <text>{{second==''?'0:00':second}}</text> </view> <view class="start_record" v-show="isStop">继续</view> <view class="three-btn row-layout" style="justify-content: space-between;"> <!-- 取消录音:×按钮 --> <view class="voice_operate row-layout" style="background: #D5D5D5;" @click="cancelVoice()"> <image src="/static/image/cancel.png" mode="widthFix"></image> </view> <!-- 暂停按钮 --> <view class="voice_middle" v-show="!isStop" @click="pauseRecording()"> <!-- 正在录音状态 --> <view class="entoch_btn"> <image src="/static/image/pauserecord.png" mode="widthFix"></image> </view> </view> <!-- 继续按钮 --> <view class="voice_middle" v-show="isStop" @click="resumeRecording()"> <!-- 暂停录音状态 --> <view class="entoch_btn"> <image src="/static/image/recording.png" mode="widthFix"></image> </view> </view> <!-- 完成录音:√按钮 --> <view class="voice_operate row-layout" @click="finishVoice()"> <image src="/static/image/finish.png" mode="widthFix"></image> </view> </view> </view> </view> </view> </view> </template> <script> import * as audioRecorder from '@/audioRecorder/methodfile.js'; //音频封装的方法文件 import profile from '@/audioRecorder/profile.js'; //音频封装的方法文件 export default { data() { return { isVoicing: false, //是否是录音状态 isFinish: false, //是否录音完成 isStop: false, //录音状态是否暂停 voiceList: [], num: 0, second: '', playing: false, times: '', //定时器 } }, methods: { //删除录音 delVoice() { this.isFinish = false this.voiceList = [] this.num = 0 this.second = '' audioRecorder.playStop(); }, //定时器:录音计时 getTimeInterval() { let t = this t.times = setInterval(() => { ++t.num; const minute = Math.floor(t.num / 60); // 获取分钟数 const miao = (t.num % 60) < 10 ? '0' + (t.num % 60) : (t.num % 60); t.second = minute + ':' + miao // 录音到规定时长会自动停止录音,需要做一些完成录音的状态修改,所以调用一下录音完成的方法 if (t.num == (profile.duration / 1000)) { t.finishVoice(); } }, 1000) }, //开始录音 startRecording() { let t = this t.isVoicing = true t.getTimeInterval(); audioRecorder.startRecording().then((result) => { uni.showToast({ title: result, duration: 500 }); }).catch((erro) => { this.cancelVoice(); uni.showModal({ title: '录音失败', content: erro }) }) }, //暂停录音 pauseRecording() { let t = this t.isStop = true audioRecorder.pauseRecording(); clearInterval(t.times) }, //继续录音 resumeRecording() { let t = this t.isStop = false audioRecorder.resumeRecording(); this.getTimeInterval(); }, //停止录音 stopRecording() { let t = this clearInterval(t.times) // 清除定时器 audioRecorder.stopRecording().then(tempFilePath => { //保存录音文件的变量清空,避免出现取消的录音存在(添加录音时,只能添加一条的情况) t.voiceList = [] t.voiceList.push({ path: tempFilePath, second: t.second }); }).catch(error => { t.$.toast('录音出错:', error) }); }, // ×取消录音,所有状态回到最初(isVoicing不是录音状态,isFinish不是完成录音,isStop不是暂停状态,isInputType显示选择输入方式) cancelVoice() { this.delVoice(); this.changeStatus(); this.stopRecording(); }, //√完成录音(isVoicing不是录音状态,isFinish录音完成状态) finishVoice() { if (this.num < 1) { uni.showToast({ icon: 'error', title: '录音时间太短', duration: 500 }); return } this.stopRecording() this.isFinish = true this.changeStatus(); }, changeStatus() { this.isVoicing = false this.isStop = false }, //播放语音 playVoice() { if (this.playing == false) { //开始播放 this.playing = true; audioRecorder.playVoiceTwo(this.voiceList[0].path, this.currentTime) // 播放时间到自动停止并销毁音频实例,释放空间 setTimeout(() => { this.playing = false; this.currentTime = 0 audioRecorder.playStop(); audioRecorder.playDestroy(); }, this.num * 1000) } else { //暂停播放 this.playing = false; audioRecorder.playPause().then(res => { this.currentTime = res }); } }, } } </script> <style lang="scss" scoped> .page-show{ margin-top: 20%; } .voice_con { background: skyblue; border-radius: 80rpx; padding: 11rpx 36rpx 11rpx 22rpx; .yy_img { width: 50rpx; height: 50rpx; margin-left: 22rpx; margin-right: 10rpx; } .time_long { font-size: 28rpx; color: white; } } .page-record { position: fixed; bottom: 0; left: 0; width: 100%; height: 350rpx; .voice_type { .vertical_center { display: flex; flex-direction: column; justify-content: center; align-items: center; .start_record { font-size: 36rpx; font-weight: bold; text-align: center; margin: 4% 0; } .entoch_btn { background: linear-gradient(180deg, rgba(19, 212, 154, 1) 0%, rgba(140, 255, 225, 1) 100%); box-shadow: 0 4rpx 12rpx 2rpx #9CFFD0; padding: 24rpx; border-radius: 50%; width: 100rpx; height: 100rpx; image { width: 100%; height: 100%; } } .three-btn { width: 100%; .voice_operate { width: 166rpx; height: 88rpx; border-radius: 100rpx; background: rgba(19, 212, 154, 1); justify-content: center; image { width: 66rpx; } } .voice_middle { text-align: center; } } } } .bgCircle { position: fixed; bottom: 0; width: 100%; height: 320rpx; z-index: -1; .bgCircleOut { position: absolute; left: 29%; transform: translateX(-29%); width: 320rpx; /* 宽度 */ height: 320rpx; /* 高度,为宽度的一半,形成半圆 */ border-radius: 50%; background-color: rgba(253, 255, 254, 0.38); box-shadow: 0rpx -10rpx 14rpx 12rpx rgba(0, 0, 0, 0.38); /* 光圈的颜色 */ animation: pulse 1.5s infinite; /* 应用名为 "pulse" 的动画,无限循环 */ } .bgCircleIn { position: absolute; bottom: 16%; left: 35.5%; transform: translateX(-35.5%); width: 220rpx; /* 宽度 */ height: 220rpx; /* 高度,为宽度的一半,形成半圆 */ border-radius: 50%; background-color: rgba(253, 255, 254, 0.38); box-shadow: 0rpx -10rpx 14rpx 12rpx rgba(196, 207, 207, 0.38); /* 光圈的颜色 */ animation: pulsetwo 1.3s infinite; /* 应用名为 "pulse" 的动画,无限循环 */ } } @keyframes pulse { 0% { transform: scale(1); /* 初始大小 */ opacity: 0.3; /* 初始透明度 */ } 50% { transform: scale(1.1); /* 放大到1.2倍大小 */ opacity: 0.3; /* 透明度减小 */ } 100% { transform: scale(1); /* 回到初始大小 */ opacity: 0.3; /* 透明度恢复 */ } } @keyframes pulsetwo { 0% { transform: scale(1); /* 初始大小 */ opacity: 0.8; /* 初始透明度 */ } 50% { transform: scale(1.1); /* 放大到1.2倍大小 */ opacity: 0.8; /* 透明度减小 */ } 100% { transform: scale(1); /* 回到初始大小 */ opacity: 0.8; /* 透明度恢复 */ } } } </style>
// 全局定义录音 let recorderManager = uni.getRecorderManager(); /** * 录音播放、暂停、继续、结束方法 */ // 开始录音 export async function startRecording() { return new Promise((resolve, reject) => { try { if (!recorderManager) { recorderManager = uni.getRecorderManager(); } // 是否开启录音权限 let permission = plus.navigator.checkPermission('RECORD'); if (permission == 'authorized') { // 应用有录音权限,可以进行录音操作 recorderManager.start({ duration: profile.duration // 录音时长:3分钟 }); } else { // 应用没有录音权限,可能需要请求用户授予录音权限 // 或者显示一个提示,告知用户需要录音权限才能进行操作 reject('应用没有录音权限'); } } catch (e) { // 如果出现错误,调用 reject 函数并传递错误信息 reject('请在app和小程序端体验录音,Uni官方明确H5不支持getRecorderManager, 详情查看Uni官方文档'); } }); } // 暂停录音 export function pauseRecording() { recorderManager.pause(); } // 继续录音 export function resumeRecording() { recorderManager.resume(); } // 结束录音 export function stopRecording() { return new Promise((resolve, reject) => { // 监听录音结束,获取音频临时路径 recorderManager.onStop(res => { resolve(res.tempFilePath); }); // 停止录音 recorderManager.stop(); }); }
let DURATION = 180000 //录音时长,毫秒
let VOLUME = 0.2 //音频播放音量0~1
const profile = {
duration: DURATION,
volume: VOLUME
};
export default profile
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。