功能比较独立&&简单,大概是这样的交互
先说录音吧,看 文档
基础功能可以这样写,挺简单的~
const recorderManager = wx.getRecorderManager()
const innerAudioContext = wx.createInnerAudioContext()
Page({
data: {
intervalId:0,
recording:false,
recordtime:0,
filePath:"",
proc:0
},
onLoad: function (options) {
recorderManager.onStart(() => {
this.setData({ recording: true })
})
recorderManager.onStop((res) => {
this.cancelRecord()
this.setData({
recording: false ,
filePath: res.tempFilePath,
})
})
recorderManager.onFrameRecorded((res) => {
const { frameBuffer } = res
console.log('frameBuffer.byteLength', frameBuffer.byteLength)
})
this.fetch();
},
startRecord: function () {
recorderManager.start(this.data.options)
this.setData({
recordtime: 0 ,
filePath: ""
})
this.data.intervalId = setInterval(()=>{
var recordtime = this.data.recordtime + 50
this.setData({
recordtime: recordtime ,
proc: recordtime / this.data.options.duration
})
}, 50);
console.log(this.data.intervalId)
},
cancelRecord: function () {
recorderManager.stop()
if (this.data.intervalId > 0){
clearInterval(this.data.intervalId)
this.data.intervalId = 0
}
},
playVoice:function(){
innerAudioContext.src = this.data.url.length > 0 ? this.data.url : this.data.filePath
innerAudioContext.play()
}
})
比较难画的是圆形进度条,这里也分享下思路:
细节是这样的:
把圆环一半设置为透明
background-image: linear-gradient(to left, transparent 50%, #F4F4F4 0);
旋转 && 50%变色
transform:rotate({{proc<0.5?proc:(proc+0.5)}}turn);
background-color: {{proc<0.5?'#F4F4F4;':'#FCDF6A'}}
下面是之前的代码
voice.js
var api = require('../../../utils/api/index.js');
var cache = require('../../../utils/api/lib/cache');
var constants = require('../../../utils/api/lib/constants.js');
const app = getApp()
const recorderManager = wx.getRecorderManager()
const innerAudioContext = wx.createInnerAudioContext()
Page({
data: {
status: 0,//1:没有录音 2:录音完成/已有录音
maxTime: 10,
recording: false,
proc:0.0,
uploading: false,
filePath:"",
url:"",
recordtime:0,
intervalId:0,
options: {
duration: 15000,
sampleRate: 44100,
numberOfChannels: 1,
encodeBitRate: 192000,
format: 'aac',
frameSize: 50
}
},
onLoad: function (options) {
recorderManager.onStart(() => {
this.setData({ recording: true })
})
recorderManager.onStop((res) => {
this.cancelRecord()
this.setData({
recording: false ,
filePath: res.tempFilePath,
status:2
})
})
recorderManager.onFrameRecorded((res) => {
const { frameBuffer } = res
console.log('frameBuffer.byteLength', frameBuffer.byteLength)
})
this.fetch();
},
onPullDownRefresh: function () {
wx.stopPullDownRefresh();
},
onShareAppMessage: () => { return app.getShare() },
fetch: function () {
wx.showNavigationBarLoading();
api.user.fetch({
success: data => {
wx.hideNavigationBarLoading()
var user = data.user_info
if (user != null
&& user.u_base_info
&& user.u_base_info.voice_desc) {
var voice = user.u_base_info.voice_desc;
if (voice.url.length > 0){
this.setData({
url: voice.url,
recordtime: voice.seconds*1000,
status: 2
})
}else{
this.setData({ status: 1 })
}
} else {
this.setData({ status: 1 })
}
},
fail: resp => {
this.setData({ status: 1 })
var msg = '错误:';
if (error.code) msg += error.code;
if (error.message) msg += error.message;
wx.showToast({ title: msg, duration: 2000 })
}
})
},
startRecord: function () {
recorderManager.start(this.data.options)
this.setData({
recordtime: 0 ,
url: ""
})
this.data.intervalId = setInterval(()=>{
var recordtime = this.data.recordtime + 50
this.setData({
recordtime: recordtime ,
proc: recordtime / this.data.options.duration
})
}, 50);
},
cancelRecord: function () {
recorderManager.stop()
if (this.data.intervalId > 0){
clearInterval(this.data.intervalId)
this.data.intervalId = 0
}
},
playVoice:function(){
innerAudioContext.src = this.data.url.length > 0 ? this.data.url : this.data.filePath
innerAudioContext.play()
},
tapDelete:function(){
wx.showNavigationBarLoading()
api.user.modify({
data: {
u_base_info: JSON.stringify({
voice_desc: { url: "", seconds: 0 }
})
},
success: resp => {
wx.hideNavigationBarLoading()
this.setData({
status: 1,
url: ""
})
}
})
},
tapUpload:function(){
var filePath = this.data.filePath;
var fileName = filePath.match(/(wxfile:\/\/)(.+)/)
if (!fileName) {
fileName = filePath.match(/(http:\/\/tmp\/)(.+)/)
}
fileName = fileName[2]
api.upload.uploadFn({
data: {
filePath: filePath,
object_name: fileName,
file_type: constants.FILE_TYPE.VOICE
},
success: data => {
// update user info
this.setData({ url: data.cdn_access_url})
api.user.modify({
data: {
u_base_info: JSON.stringify({
voice_desc: {
url: data.cdn_access_url,
seconds: parseInt(this.data.recordtime/1000)
}
})
},
success: resp => {
wx.hideNavigationBarLoading()
wx.showToast({ title: '保存成功', duration: 1500 })
setTimeout(function () { wx.navigateBack(); }, 1500)
app.event.emit("onSettingModify", {
full: false,
u_base_info:{
voice_desc: {
url: data.cdn_access_url,
seconds: parseInt(this.data.recordtime / 1000)
}
}
})
}
})
},
fail: err => {
wx.hideNavigationBarLoading()
wx.showToast({ title: '上传失败', duration:1500 })
},
onProgress: info => {},
onStartUpload: info => {
wx.showNavigationBarLoading()
}
})
}
})
voice.wxml
<view class="voice">
<view wx:if="{{status==1}}" class="recording">
<view wx:if="{{recording}}" class="title">录音中view>
<view wx:else class="title">你还没有语音view>
<view class="foot">
<view
class="{{recording?'btn-ing':'btn'}}"
bindtouchend='cancelRecord'
bindtouchstart='startRecord'>
<view
class="process"
style="transform:rotate({{proc<0.5?proc:(proc+0.5)}}turn);background-color: {{proc<0.5?'#F4F4F4;':'#FCDF6A'}}">
view>
<view class="cont">
<image src="{{recording?'/image/v3/icon_speaking.png':'/image/v3/icon_speak.png'}}">image>
view>
view>
<view>{{recording?'松开结束':'按住录音'}}view>
view>
view>
<view wx:if="{{status==2}}" class="record-done">
<view class="title">录音完成view>
<view class="play" bindtap="playVoice">
<span>{{recordtime/1000}}”span>
<image src="/image/v3/voice.png">image>
view>
<view class="foot">
<view bindtap="tapDelete" class="del">
<image src="/image/v3/icon_speak_close.png">image>
view>
<view bindtap="tapUpload" class="done">
<image src="/image/v3/icon_speak_done.png">image>
view>
view>
view>
view>
voice.wxss
.voice{
text-align: center;
color: #787878;
}
.voice .title{
font-size: 34rpx;
padding-top: 238rpx;
}
.voice .recording .foot{
font-size: 30rpx;
position: absolute;
bottom: 224rpx;
left: 0;
right: 0;
}
.voice .recording .foot image{
width: 74rpx;
height: 104rpx;
}
.voice .recording .foot .btn{
width: 192rpx;
height: 192rpx;
border-radius: 192rpx;
box-sizing: border-box;
background: -webkit-linear-gradient(left, #CB6BCF, #EF6790, #FC5045);
margin: 0 auto 44rpx auto;
padding: 6rpx;
}
.voice .recording .foot .btn .cont{
width: 180rpx;
height: 180rpx;
background-color: #f4f4f4;
border-radius: 180rpx;
padding-top: 40rpx;
box-sizing:border-box;
}
.voice .recording .foot .btn-ing{
position: relative;
width: 216rpx;
height: 216rpx;
border-radius: 216rpx;
box-sizing: border-box;
background: #FCDF6A;
margin: 0 auto 32rpx auto;
background-image: linear-gradient(to left, transparent 50%, #F4F4F4 0);
}
.voice .recording .foot .btn-ing .cont{
position: absolute;
right: 12rpx;
top: 12rpx;
bottom: 12rpx;
left: 12rpx;
z-index: 2;
width: 192rpx;
height: 192rpx;
background: -webkit-linear-gradient(left, #CB6BCF, #EF6790, #FC5045);
border-radius: 192rpx;
padding-top: 44rpx;
box-sizing:border-box;
}
.voice .recording .foot .btn-ing .process{
z-index: 1;
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 108rpx;
border-radius: 0 100% 100% 0 / 50%;
transform-origin:0rpx 108rpx;
}
.voice .record-done .play{
position: relative;
width: 248rpx;
height: 72rpx;
border-radius: 72rpx;
background: -webkit-linear-gradient(left, #CB6BCF, #EF6790, #FC5045);
color: white;
font-size: 28rpx;
line-height: 72rpx;
text-align: left;
padding-left: 60rpx;
box-sizing: border-box;
margin: 194rpx auto 0 auto;
}
.voice .record-done .play image{
position: absolute;
right: 36rpx;
top: 10rpx;
width: 52rpx;
height: 52rpx;
}
.voice .record-done .foot{
position: absolute;
bottom: 210rpx;
left: 0;
right: 0;
}
.voice .record-done .foot>view{
width: 106rpx;
height: 106rpx;
border-radius:106rpx;
display:inline-block;
box-shadow: 0rpx 5rpx 10rpx 3rpx #c2c2c2;
}
.voice .record-done .foot .del{
background-color: #C2C2C2;
}
.voice .record-done .foot .done{
margin-left: 136rpx;
background: -webkit-linear-gradient(left, #CB6BCF, #EF6790, #FC5045);
}
.voice .record-done .foot .del image{
width: 39rpx;
height: 39rpx;
margin-top: 34rpx;
}
.voice .record-done .foot .done image{
width: 55rpx;
height: 33rpx;
margin-top: 34rpx;
}
玩~