sadjv3_user/my/components/jc-record/jc-record.vue

391 lines
9.1 KiB
Vue
Raw Normal View History

2024-06-05 19:16:02 +08:00
<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>