sadjv3/anmo-user/my/components/jc-record/jc-record.vue

391 lines
9.1 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="jsfun-record" @tap="showPicker">
<slot></slot>
<!-- 遮罩层 -->
<view class="mask" @tap.stop="closePicker" v-if="isShow" @touchmove.stop.prevent="moveHandle"></view>
<!-- 多选控件 -->
<view class="conbox record" :class="{'pickerShow':isShow}">
<!-- 此处可放置倒计时,可根据需要自行添加 -->
<view class="time">
{{showRecordTime}}
</view>
<view class="c999">
最短{{minTime}}秒,最长{{maxTime}}秒
</view>
<view class="record-box" @touchstart="start" @longpress="record" @touchend="end"
@touchmove.stop.prevent="moveHandle">
<span class="stop" @touchstart.stop="stopVoice" v-if="voicePath && playing==1"></span>
<span class="paly" @touchstart.stop="playVoice" v-if="voicePath && playing==0"></span>
<canvas class="canvas" canvas-id="canvas">
<span class="recording"></span>
</canvas>
<span class="confirm" @touchstart.stop="okClick" v-if="voicePath"></span>
</view>
<view class="c666 fz32 domess">长按录音</view>
</view>
</view>
</template>
<script>
const recorderManager = uni.getRecorderManager(); //录音
var innerAudioContext; //播放
export default {
name: 'jsfun-record',
props: {
maxTime: { // 录音最大时长,单位秒
type: Number,
default: 15
},
minTime: { // 录音最大时长,单位毫秒
type: Number,
default: 5
},
},
data() {
return {
isShow: false,
frame: 50, // 执行绘画的频率,单位毫秒
recordTime: 0, //录音时长
recordTime1: 0, //播放录音倒计时
isshowyuan: false, //是否显示圆圈
playing: 0, //是否播放中
timeObj: null, //计时id
drawObj: null, //画布动画id
countdownObj: null, //倒计时id
voicePath: '',
ctx: ''
}
},
computed: {
showRecordTime() {
var strs = "";
var m = Math.floor(this.recordTime / 60);
if (m < 10) strs = "0" + m;
var s = this.recordTime % 60;
strs += (s < 10) ? ":0" + s : ":" + s;
return strs
},
},
watch: {},
onLoad() {
var _this = this;
//获取录音权限
uni.authorize({
scope: 'scope.record',
success() {}
})
//初始化
_this.initValue();
},
mounted() {
innerAudioContext = uni.createInnerAudioContext(); //播放
let _this = this;
//录音停止事件
recorderManager.onStop(function(res) {
console.log('recorder stop' + res.tempFilePath);
_this.voicePath = res.tempFilePath;
});
//根据canvas 动态中心点
let query = uni.createSelectorQuery().in(this);
query.select(".canvas").boundingClientRect()
query.exec(function(res) {
_this.tempw = res[0].width; //使用canvas的宽度计算中心点的位置
_this.temph = res[0].height;
})
//根据中心图片的大小计算圆环的大小
query.select(".recording").boundingClientRect()
query.exec(function(res) {
_this.tempw1 = res[0].width; //使用点按图形的宽度计算圆环的宽高
})
},
beforeDestroy() {
innerAudioContext.destroy();
},
methods: {
moveHandle() {
return false;
},
//组件数据初始化 进入时、关闭时调用初始化
initValue() {
this.recordTime = 0
},
//显示组件
showPicker() {
setTimeout(() => {
this.isShow = true;
// this.$emit('show');
}, 100);
},
//关闭组件
closePicker() {
this.isShow = false;
//点遮罩 点取消关闭说明用户不想修改,所以这里对数据进行初始化
this.initValue();
this.stopVoice();
},
//点击确定
okClick() {
// var data = {},list = {},textStr = "",indexStr = "";
this.$emit('okClick', this.voicePath)
this.$emit('start', 2)
//确定后更新默认初始值,这样再次进入默认初值就是最后选择的
// this.defaultArr = textStr;
//关闭
this.closePicker();
},
start() {
console.log('start')
this.stopVoice();
this.voicePath = ""; //音频地址
this.recordTime = 0;
//生成canvas对象
this.ctx = uni.createCanvasContext('canvas',this);
},
end() {
console.log('end')
let recordTime = this.recordTime;
this.recordTime1 = this.recordTime;
clearInterval(this.timeObj); //清除计时器
clearInterval(this.drawObj); //清除画布动画
// this.recordTime = 0; //清除计时
this.isshowyuan = false; //隐藏圆圈
//清除canvas内容 方式一:不知道为啥 不起作用
//this.ctx.clearRect(0,0,this.ctx.width,this.ctx.height);
//清除canvas内容 方式二填充canvas为白色
this.ctx.setFillStyle('#fff')
this.ctx.fillRect(0, 0, this.ctx.width, this.ctx.height)
this.ctx.draw()
if (recordTime < this.minTime) {
if (recordTime <= 0) {
//==点击事件==;
return false;
}
//==小于5秒==;
uni.showToast({
title: "不能小于" + this.minTime + "秒,请重新录制",
icon: "none"
})
return false;
}
recorderManager.stop();
},
record: function() {
console.log('record')
let _this = this;
_this.isshowyuan = true
// 开始录音
recorderManager.start({
format: "mp3"
});
_this.timeObj = setInterval(function() {
_this.recordTime++;
if (_this.recordTime == _this.maxTime) _this.end();
}, 1000);
//中心点坐标 这里如果直接除2发现位置有偏差目前还没明白为什么要减1
let pianyi = 0
switch (uni.getSystemInfoSync().platform) {
case 'android':
pianyi = 0;
break;
case 'ios':
pianyi = 1;
break;
default:
pianyi = 1;
break;
}
// #ifdef APP-PLUS
let centerX = _this.tempw / 2 + pianyi;
let centerY = _this.temph / 2 + pianyi;
// #endif
// #ifdef MP-WEIXIN
let centerX = _this.tempw / 2 + pianyi-1;
let centerY = _this.temph / 2 + pianyi-1;
// #endif
let yuanhuanW = _this.tempw1 / 2 -6; //圆环的半径 中间图片的宽度/2 + 4
// 录音过程圆圈动画的背景园
_this.ctx.beginPath();
_this.ctx.setStrokeStyle("#1789FD");
_this.ctx.setGlobalAlpha(0.3)
_this.ctx.setLineWidth(3);
_this.ctx.arc(centerX, centerY, yuanhuanW, 0, 2 * Math.PI);
_this.ctx.stroke();
_this.ctx.draw();
// 录音过程圆圈动画
let angle = -0.5;
_this.drawObj = setInterval(function() {
_this.ctx.beginPath();
_this.ctx.setStrokeStyle("#1789FD");
_this.ctx.setGlobalAlpha(1)
_this.ctx.setLineWidth(3);
_this.ctx.arc(centerX, centerY, yuanhuanW, -0.5 * Math.PI, (angle += 2 / (_this
.maxTime * 1000 / _this.frame)) * Math.PI, false);
_this.ctx.stroke();
_this.ctx.draw(true);
}, _this.frame);
},
playVoice() {
if (this.voicePath && this.playing === 0) {
innerAudioContext.src = this.voicePath;
innerAudioContext.stop(); //todo 第一次play时若不先stop则播放不出来,未知原因
innerAudioContext.play();
this.playing = 1;
this.recordTime = this.recordTime1;
this.countdownObj = setInterval(() => {
this.recordTime--;
if (this.recordTime === 0) {
this.stopVoice()
return;
}
}, 1000)
}
},
stopVoice() {
innerAudioContext.stop();
this.playing = 0;
this.recordTime = 0;
clearInterval(this.countdownObj);
},
}
}
</script>
<style lang="scss">
.jsfun-record {
.mask {
position: fixed;
z-index: 1000;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
}
.conbox {
transition: all .3s ease;
transform: translateY(100%);
&.pickerShow {
transform: translateY(0);
}
position: fixed;
z-index: 1000;
right: 0;
left: 0;
bottom: 0;
background: #fff;
}
.c666 {
color: #666;
}
.c999 {
color: #999;
}
.fz28 {
font-size: 28upx;
}
.fz32 {
font-size: 32upx;
}
.record {
text-align: center;
.time {
text-align: center;
font-size: 60upx;
color: #000;
line-height: 100upx;
margin-top: 50upx;
}
.domess {
margin-bottom: 50upx;
}
.record-box {
display: flex;
flex-direction: row;
justify-content: center;
}
canvas {
margin: 10upx 60upx;
position: relative;
width: 200upx;
height: 200upx;
z-index: 10;
.recording {
position: absolute;
top: 20upx;
left: 20upx;
width: 160upx;
height: 160upx;
border: 1px dashed #1789FD;
border-radius: 100upx;
background: #1789FD url(../../static/jsfun-record/recording.png) no-repeat 50% 50%;
background-size: 50% 50%;
z-index: 100;
}
}
.btncom {
margin-top: 70upx;
width: 80upx;
height: 80upx;
border-radius: 80upx;
}
.stop {
@extend .btncom;
background: #1789FD url(../../static/jsfun-record/stop.png) no-repeat;
background-size: 100% 100%;
}
.paly {
@extend .btncom;
background: #1789FD url(../../static/jsfun-record/play.png) no-repeat;
background-size: 100% 100%;
}
.confirm {
@extend .btncom;
background: url(../../static/jsfun-record/confirm.png) no-repeat 100% 100%;
background-size: 100% 100%;
}
}
}
</style>