uniapp录音方法的使用说明
设计思路:
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、删除录好的音频需要判断一下是否在播放,如果在播放就结束播放然后删除录好的音频
附上源码:
vue文件:record.vue
<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>
方法文件:methodfile.js
// 全局定义录音
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();
});
}
配置文件:profile.js
let DURATION = 180000 //录音时长,毫秒
let VOLUME = 0.2 //音频播放音量0~1
const profile = {
duration: DURATION,
volume: VOLUME
};
export default profile