完整代码,请读者耐心看完
注意
- 首先创建录音对象
const recorderManager = wx.getRecorderManager()
const innerAudioContext = wx.createInnerAudioContext()
- 录音功能,授权与拒绝授权的逻辑处理
wx.authorize({
scope: 'scope.record',
success() {
that.stratRecordAudio()
},
fail() {
wx.showModal({
title: '提示',
content: '您未授权录音,功能将无法使用',
showCancel: true,
confirmText: "授权",
confirmColor: "#2D59DF",
success: function (res) {
if (res.confirm) {
//确认则打开设置页面(重点)
wx.openSetting({
success: (res) => {
if (!res.authSetting['scope.record']) {
//未设置录音授权
wx.showModal({
title: '提示',
content: '您未授权录音,功能将无法使用',
showCancel: false,
success: function (res) {},
})
} else {
that.stratRecordAudio()
}
},
fail: function () {
console.log("授权设置录音失败");
}
})
} else if (res.cancel) {
console.log("cancel");
}
},
fail: function () {
console.log("openfail");
}
})
}
})
- 临时录音文件,要转存我们自己项目的资源站
// 传到资源保存站
wx.uploadFile({
url: uploadAudio.uploadAudio,
filePath: that.data.filePath,
name: 'file',
success(res) {
filePath = JSON.parse(res.data).data[0]
var params = {
userId: that.data.userId,
url: filePath,
duration: that.data.duration,
type: 2
}
//真正传到数据库
postRecording(params).then(res => {
wx.hideLoading()
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
})
wx.navigateTo({
url: '/pages/card/package-1st/pages/card-change/cardChange?userId=' + that.data.userId,
})
})
}
})
wxss
page{
background-color:#F3F3F7;
}
.editWrapBox {
background-color: #ffffff;
margin-bottom: 10px;
overflow: hidden;
position: relative;
}
.headerContentWrap{
margin:0 auto;
padding: 30px 0;
box-sizing: border-box;
}
.headerInWrapItem{
width:100vw;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.luyinWrap,.luyinWrap2,.luyinWrap3{
width: 90px !important;
height: 90px !important;
line-height:75px !important;
border-radius: 50% !important;
text-align: center !important;
margin: 0;
}
.luyinWrap{
background-color:#F1F3F8 !important;
}
.luyinWrap2{
background-color:#2D59DF !important;
}
.luyinWrap3{
background-color:#2D59DF;
position: absolute;
top: 25px;
}
.icon-maikefenghuatongyuyin{
font-size: 35px;
color: #2D59DF;
}
.icon{
font-size: 35px;
color: #ffffff;
}
.icon-bofanganniu,.icon-iconstop{
font-size: 25px;
color: #ffffff;
}
.actionName{
margin-top: 14px;
font-size: 14px;
color: #333333;
}
.numberSize,.delText{
color: #E50000;
}
.delText{
font-size: 14px;
width: 55px;
height: 55px;
text-align: center;
line-height: 55px;
margin-top: 27px;
border: 1px solid #E50000;
border-radius: 50%;
}
.progressWrap {
width: 100vw;
height: 40px;
line-height: 40px;
margin:0px auto;
background-color: #BCCDFF;
font-size: 14px;
text-align: center;
color: #333333;
}
.luyinOutWrap.active{
background-color: #BCCDFF;
opacity: 1;
animation: scale 2.5s infinite ease alternate;
}
.luyinOutWrap{
width:120px;
height:120px;
text-align: center;
margin: 10px auto;
border-radius: 50%;
}
@keyframes scale {
0% {
opacity:1
}
25% {
opacity:0.75
}
45% {
opacity:0.5
}
50% {
opacity:0.25
}
75% {
opacity:0.5
}
85% {
opacity:0.75
}
100% {
opacity:1
}
}
.saveinfo {
font-size: 16px !important;
color: #ffff !important;
text-align: center !important;
background-color: #2D59DF !important;
border-radius: 20px !important;
width:95% !important;
position: fixed !important;
bottom: 10px !important;
left: 10px !important;
}
wxml
<view class="editWrapBox">
<!-- 未录音 -->
<view class="headerContentWrap" wx:if="{{noRecordShow}}">
<view class="headerInWrapItem">
<button class="luyinWrap" bindtap="authorize"><i class="iconfont icon-maikefenghuatongyuyin"></i></button>
<view class="actionName">点击录音</view>
</view>
</view>
<!-- 录制语音中 -->
<view wx:if="{{recordLuzhiShow}}">
<view class="progressWrap">
录音中(已录制<text class="numberSize">{{countNume}}s</text>),再次点击按钮即可停止录制
</view>
<view class="headerContentWrap">
<view class="headerInWrapItem">
<view class="luyinOutWrap active"></view>
<button class="luyinWrap3" bindtap="stopRecordAudio"><i
class="iconfont icon-maikefenghuatongyuyin icon"></i></button>
</view>
</view>
</view>
<!-- 播放语音中 -->
<view wx:if="{{playAudioShow}}">
<view class="progressWrap">
播放中...
</view>
<view class="headerContentWrap">
<view class="headerInWrapItem">
<view class="luyinOutWrap active"></view>
<button class="luyinWrap3"><i class="iconfont icon-iconstop"></i></button>
</view>
</view>
</view>
<!-- 录音完成 -->
<view class="headerContentWrap" wx:if="{{finishRecordShow}}">
<view class="headerInWrapItem">
<view bindtap="playRecordAudio" data-type="1"> <button class="luyinWrap2"><i class="iconfont icon-bofanganniu"></i></button>
<view class="actionName">点击播放录音1</view>
</view>
<view class="delText" bindtap="recycleRecordAudio">重录</view>
</view>
</view>
<!--已经存在语音 -->
<view class="headerContentWrap" wx:if="{{extistRecordShow}}">
<view class="headerInWrapItem">
<view bindtap="playRecordAudio" data-type="2"><button class="luyinWrap2"><i class="iconfont icon-bofanganniu"></i></button>
<view class="actionName">点击播放录音2</view>
</view>
<view class="delText" bindtap="deleteRecord">删除</view>
</view>
</view>
<!-- 保存按钮 -->
<button class="saveinfo" wx:if="{{finishRecordShow}}" bindtap="saveRocordAudio">保存</button>
</view>
js
const recorderManager = wx.getRecorderManager()
const innerAudioContext = wx.createInnerAudioContext()
var init
==语音删除、保存接口==
import {
postRecording,
deleteRecording
} from '../../../../../config/api/cardUrl'
import {
uploadAudio
} from '../../../../../config/basicConfig' //语音保存地址
Page({
data: {
noRecordShow: true, //初始显示
recordLuzhiShow: false, //控制录制
finishRecordShow: false, //完成录音
extistRecordShow: false, //已存在录音
playAudioShow: false, //播放按钮
exisiFilePath: '', //已经存在的录音
countNume: 0, // 倒计时
filePath: '', // 临时语音录制文件
duration: 0, // 录制时间
userId: 0, //用户id
id: 0, //语音id
},
onLoad: function (options) {
this.setData({
userId: parseInt(options.userId),
id: parseInt(options.id)
})
if (options.filePath == "undefined") {
this.setData({
extistRecordShow: false,
noRecordShow: true,
})
} else {
this.setData({
exisiFilePath: options.filePath,
extistRecordShow: true,
noRecordShow: false,
})
}
},
// 语音授权
authorize() {
var that = this
wx.authorize({
scope: 'scope.record',
success() {
that.stratRecordAudio()
},
fail() {
wx.showModal({
title: '提示',
content: '您未授权录音,功能将无法使用',
showCancel: true,
confirmText: "授权",
confirmColor: "#2D59DF",
success: function (res) {
if (res.confirm) {
//确认则打开设置页面(重点)
wx.openSetting({
success: (res) => {
if (!res.authSetting['scope.record']) {
//未设置录音授权
wx.showModal({
title: '提示',
content: '您未授权录音,功能将无法使用',
showCancel: false,
success: function (res) {},
})
} else {
that.stratRecordAudio()
}
},
fail: function () {
console.log("授权设置录音失败");
}
})
} else if (res.cancel) {
console.log("cancel");
}
},
fail: function () {
console.log("openfail");
}
})
}
})
},
//录音计时器
recordingTimer: function (time) {
var that = this
if (time == undefined) {
//将计时器赋值给init
init = setInterval(function () {
var time = that.data.countNume + 1;
that.setData({
countNume: time
})
}, 1000);
} else {
clearInterval(init)
}
},
// 开始录音
stratRecordAudio() {
clearInterval(init) //清除定时器
// 监听音频开始事件
this.setData({
noRecordShow: false,
recordLuzhiShow: true
})
recorderManager.onStart((res) => {})
recorderManager.onStop((res) => {
this.setData({
recordLuzhiShow: false,
finishRecordShow: true,
filePath: res.tempFilePath,
duration: res.duration
})
this.recordingTimer(this.data.countNume)
})
const options = {
duration: this.data.duration, //指定录音的时长,单位 ms
sampleRate: 16000, //采样率
numberOfChannels: 1, //录音通道数
encodeBitRate: 96000, //编码码率
format: 'mp3', //音频格式,有效值 aac/mp3
frameSize: 50, //指定帧大小,单位 KB
}
this.recordingTimer()
recorderManager.start(options)
},
// 停止录音
stopRecordAudio() {
this.setData({
recordLuzhiShow: false,
finishRecordShow: true,
})
recorderManager.onStop((res) => {
this.setData({
filePath: res.tempFilePath,
duration: res.duration
})
})
this.recordingTimer(this.data.countNume)
recorderManager.stop()
},
// 播放录音
playRecordAudio(e) {
//在ios下静音时播放没有声音,默认为true,改为false就好了。
innerAudioContext.obeyMuteSwitch = false
var filPathType = e.currentTarget.dataset.type
if (filPathType == 1) {
this.setData({
playAudioShow: true,
finishRecordShow: false
})
innerAudioContext.src = this.data.filePath
innerAudioContext.play()
innerAudioContext.onEnded(() => {
this.setData({
playAudioShow: false,
finishRecordShow: true
})
})
} else {
this.setData({
playAudioShow: true,
extistRecordShow: false
})
innerAudioContext.src = this.data.exisiFilePath
innerAudioContext.play()
innerAudioContext.onEnded(() => {
this.setData({
playAudioShow: false,
extistRecordShow: true
})
})
}
},
// 重新录音
recycleRecordAudio() {
var that = this
wx.showModal({
title: "重新录音",
content: "是否重新录制?",
success(res) {
if (res.confirm) {
that.setData({
noRecordShow: true, //初始显示
recordLuzhiShow: false, //控制录制
finishRecordShow: false, //完成录音
extistRecordShow: false, //已存在录音
playAudioShow: false, //播放按钮
filePath: '',
countNume: 0,
duration: 0
})
innerAudioContext.stop()
}
}
})
},
// 保存录音
saveRocordAudio() {
wx.showLoading({
title: '保存中...',
})
var filePath = "",
that = this
wx.uploadFile({
url: uploadAudio.uploadAudio,
filePath: that.data.filePath,
name: 'file',
success(res) {
filePath = JSON.parse(res.data).data[0]
var params = {
userId: that.data.userId,
url: filePath,
duration: that.data.duration,
type: 2
}
postRecording(params).then(res => {
wx.hideLoading()
wx.showToast({
title: '保存成功',
icon: 'success',
duration: 2000
})
wx.navigateTo({
url: '/pages/card/package-1st/pages/card-change/cardChange?userId=' + that.data.userId,
})
})
}
})
},
// 删除语音
deleteRecord() {
var that = this
wx.showModal({
title: '提示',
content: '确定要删除语音吗?',
success(res) {
if (res.confirm) {
deleteRecording(that.data.id).then(res => {
wx.showToast({
title: '删除成功',
icon: 'success',
duration: 2000
})
wx.navigateTo({
url: '/pages/card/package-1st/pages/card-change/cardChange?userId=' + that.data.userId,
})
})
}
}
})
},
})