提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
因工作需要,开发录音功能,实现长按录制语音,4秒后自动停止,松开上传,使用了uview的圆形进度条来实现录制中的音阶动效,
一、getRecorderManager
获取全局唯一的录音管理器 RecorderManager
二、实现方法
代码如下:
html
<template>
<view class="tape-module">
<button class="record-btn flex-center" @longtap="recordingStatusBtn" @touchend="touchendBtn()"
@touchmove="handleTouchMove" @touchstart="recordingStatusBtn">
<text
v-if="recordingStatus == 1 || recordingStatus == 5 || recordingStatus == 6 || recordingStatus == 7">按住开始录制</text>
<text v-if="recordingStatus == 2">说话中</text>
<text v-if="recordingStatus == 4">上传中...</text>
</button>
<view class="cancel" v-if="delShow">
取消 上传
</view>
<view :class="'ly-close flex-center ' + (delShow ? 'select' : '')" @tap="delBtn" v-if="recordingStatus != 3">
<text class="iconfont icon-guanbi"></text>
</view>
<view
:class="'tape-box flex-center ' + (recordingStatus == 2 ? 'column' : (recordingStatus == 4 || recordingStatus == 5) ? 'tape-error' : '')"
v-if="!delShow">
<view class="tape-tips" v-if="recordingStatus == 1">
请按住下方按钮开始录制
</view>
<block v-if="recordingStatus == 2">
<view class="u-press">
<u-circle-progress inactive-color="#06AD56" width="100" border-width="6" active-color="#ffffff"
:percent="tapePress" duration="4500" bg-color="transparent">
<view class="prompt-loader">
<view class="em" v-for="(item,index) in 5" :key="index"></view>
</view>
</u-circle-progress>
</view>
<view class="tape-title">
正在录制一段您的专属人声片段
</view>
</block>
<view class="succ-title" v-if="recordingStatus == 3">
录制成功
</view>
<view class="error-title" v-if="recordingStatus == 5">
您说话的时间太短了<br>重新录入
</view>
<view class="error-title" v-if="recordingStatus == 4">
内容存在敏感信息<br>请重新上传
</view>
</view>
</view>
</template>
2.js代码逻辑
<script>
import uCircleProgress from "../../uni_modules/uview-v1_1/components/u-circle-progress/u-circle-progress.vue";
const recorderManager = uni.getRecorderManager()
var percentTime = null
var uploadLyTime = null
export default {
components: {
uCircleProgress,
},
data() {
return {
recordingStatus: 1, // 1按住说话 2说话中 3 录制成功 4敏感 5时间太短
delShow: false, // 删除提示框显示隐藏
duration: 4000, //录音最大值ms 4秒
url: '', //音频路径
startPoint: {}, //记录录音开始点信息
lock: true,
tapePress: 0
}
},
onLoad(options) {
recorderManager.onStop((res) => {
clearInterval(uploadLyTime)
uploadLyTime = null
this.tapePress = 100
if (!this.lock) {
if (res.duration > 3000 && res.duration < 5000) {
//进入上传保存方法
this.recordingStatus = 3;
this.url = res.tempFilePath
// this.saveVideo(res.tempFilePath)
} else {
this.recordingStatus = 5
}
}
})
},
methods: {
saveVideo(data) {
uni.uploadFile({
url: '敏感校验接口',
filePath: data,
name: 'file',
success(res) {
if (res.data.code == '0000') {
this.recordingStatus = 3
setTimeout(() => {
this.recordingStatus = 1
}, 1000)
} else {
this.recordingStatus = 4
setTimeout(() => {
this.recordingStatus = 1
}, 1000)
}
},
fail(error) {
uni.showToast({
title: '系统开小差了',
icon: 'none'
})
}
})
},
recordingStatusBtn(e) {
this.startPoint = e.touches[0];
this.recordingStatus = 2;
const options = {
duration: this.duration,
format: 'mp3',
}
recorderManager.start(options);
this.tapePress = 0
uploadLyTime = setInterval(() => {
this.tapePress = this.tapePress + 25
}, 1000)
this.lock = false;
},
touchendBtn() {
recorderManager.stop(); //结束录音
},
handleTouchMove(e) {
let moveY = e.touches[0].clientY - this.startPoint.clientY; //移动距离
let moveX = e.touches[0].clientX - this.startPoint.clientX;
console.log(moveY)
if (moveY < -100) {
this.delShow = true
this.lock = true
this.recordingStatus = 1
} else {
this.delShow = false
this.lock = false
}
},
delBtn() {
this.delShow = false
this.recordingStatus = 1
}
}
}
</script>
3.css样式
<style scoped lang="less">
.tape-module {
width: 100%;
height: 100vh;
background: #141414;
.record-btn {
width: 100%;
height: 244rpx;
background: linear-gradient(180deg, #FFFFFF 0%, #D5D5D5 100%);
position: absolute;
bottom: 0;
font-weight: 600;
font-size: 28rpx;
color: #464646;
font-style: normal;
z-index: 25;
}
.ly-close {
width: 144rpx;
height: 144rpx;
position: absolute;
left: 60rpx;
bottom: 266rpx;
z-index: 25;
background: #333333;
border-radius: 50%;
text {
color: #8F8F8F;
font-size: 38rpx;
}
}
.select {
background: #FA5251;
}
.tape-box {
width: 388rpx;
height: 198rpx;
position: absolute;
background: #07C160;
z-index: 25;
left: 182rpx;
bottom: 680rpx;
border-radius: 16rpx;
.tape-tips {
width: 100%;
height: 40rpx;
font-weight: 600;
font-size: 28rpx;
color: #FFFFFF;
line-height: 40rpx;
font-style: normal;
text-align: center;
line-height: 40rpx;
}
.u-press {
width: 100rpx;
height: 100rpx;
}
.tape-title {
width: 224rpx;
height: 80rpx;
font-weight: 600;
font-size: 28rpx;
color: #FFFFFF;
line-height: 40rpx;
text-align: center;
font-style: normal;
}
.prompt-loader {
width: 48rpx;
height: 38rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.prompt-loader .em {
display: block;
background: #fff;
width: 1px;
height: 40%;
margin-right: 2.5px;
float: left;
}
@keyframes load {
0% {
height: 40%;
}
50% {
height: 100%;
}
100% {
height: 40%;
}
}
.prompt-loader .em:last-child {
margin-right: 0px;
}
.prompt-loader .em:nth-child(1) {
animation: load 2.5s 1.6s infinite linear;
}
.prompt-loader .em:nth-child(2) {
animation: load 2.5s 1.8s infinite linear;
}
.prompt-loader .em:nth-child(3) {
animation: load 2.5s 1s infinite linear;
}
.prompt-loader .em:nth-child(4) {
animation: load 2.5s 1.8s infinite linear;
}
.prompt-loader .em:nth-child(5) {
animation: load 2.5s 1.6s infinite linear;
}
.succ-title {
width: 196rpx;
height: 40rpx;
font-weight: 600;
font-size: 28rpx;
color: #FFFFFF;
line-height: 40rpx;
text-align: center;
font-style: normal;
}
.error-title {
width: 344rpx;
height: 80rpx;
font-weight: 600;
font-size: 28rpx;
color: #FFFFFF;
line-height: 40rpx;
text-align: center;
font-style: normal;
}
}
.cancel {
width: 100%;
height: 40rpx;
font-weight: 600;
font-size: 28rpx;
color: #B2B2B2;
line-height: 40rpx;
text-align: left;
font-style: normal;
position: absolute;
bottom: 442rpx;
padding: 0 70rpx;
box-sizing: border-box;
z-index: 24;
}
.tape-error {
background-image: #FA5251;
}
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.column {
flex-direction: column;
}
</style>