1.创建子组件chatAudio.vue
<template>
<view class="chatAudio">
<view class="audioPlay" v-if="show">
<view class="content">
<!-- 录制中动图,底色变化 -->
<view class="gif" :class="{
'red':closeShow}">
<image src="../../static/img/33.gif" mode=""></image>
</view>
<view class="close">
<!-- ×号 颜色变化-->
<image src="../../static/img/32.png" mode="" v-if="!closeShow"></image>
<image src="../../static/img/28.png" mode="" v-if="closeShow"></image>
</view>
<view class="bom">
<text v-if="!closeShow">松开 发送</text>
<text v-if="closeShow">松开 取消</text>
<!-- 底图颜色变化 -->
<image src="../../static/img/30.png" mode="" v-if="!closeShow"></image>
<image src="../../static/img/31.png" mode="" v-if="closeShow"></image>
<!-- 计时器 -->
<view class="times">
<u-circle-progress active-color="#6C9FEB" :percent="times" bg-color="" width="140" border-width="7"></u-circle-progress>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
const recorderManager = uni.getRecorderManager();
const innerAudioContext = uni.createInnerAudioContext();
innerAudioContext.autoplay = true;
export default {
name: 'chatAudio',
props: {
audioShow: {
type: Boolean,
default: false
},
audioXY: {
type: Object,
},
audioTouchendShow: {
type: Boolean,
default: false
},
},
watch: {
// audioShow:true录制界面显示,开始录音,false关闭。
audioShow(e, oldVal) {
if(e){
console.log('开始录音')
this.status = 0;
this.audioSrc = '';
this.number = 1;
this.show = true;
// 计算录制时长,>=60 录制结束
this.times = 1;
this.timesInt = setInterval(() => {
this.times ++;
console.log(this.times)
if(this.times>= 60){
clearInterval(this.timesInt);
this.closeShow = false;
recorderManager.stop();
console.log('结束录制');
}
}, 1000);
// 开始录制
recorderManager.start();
// 获取关闭按钮.close在屏幕中的位置信息
this.$nextTick(()=>{
let close = uni.createSelectorQuery().select(".close");
close.boundingClientRect((data)=> {
this.dom = data;
}).exec()
})
}else{
this.show = false;
}
},
// 手指在屏幕中的位置,判断是否:录制中/删除
audioXY(e){
let x = e.x;
let y = e.y;
let left = this.dom.left;
let top = this.dom.top;
if(x>left && x<left+this.dom.width && y>top && y<top+this.dom.height){
this.closeShow = true;
}else{
this.closeShow = false;
}
},
// 手指结束触摸,通知父组件关闭弹窗,根据this.closeShow类型,判断是取消还是发送
audioTouchendShow(e){
this.$emit('closeAudioShow')
if(this.number == 1){
this.number++;
if(this.closeShow){
console.log('取消录制')
clearInterval(this.timesInt);
this.closeShow = false;
recorderManager.stop();
}else{
console.log('发送音频');
clearInterval(this.timesInt);
this.closeShow = false;
recorderManager.stop();
this.status = 1;
}
}
}
},
data() {
return {
show:false, // 弹窗
closeShow:false, // 正常/删除
winSize:{
},
dom:{
}, // 删除按钮位置
times:1, // 计时器
timesInt:null, // 计时器
status:0, //0录制中,1录制结束。
number:1,
}
},
mounted() {
// 录音停止事件,会回调文件地址,如果status == 1,上传音频,并通知父组件发送音频信息
recorderManager.onStop((res)=> {
console.log(res)
this.audioSrc = res.tempFilePath;
if(this.status == 1){
this.upload(this.audioSrc, 'audio');
}
});
uni.getSystemInfo({
success: (res) => {
this.winSize = {
"witdh": res.windowWidth,
"height": res.windowHeight
}
}
})
},
methods: {
// 上传音频,并发送
upload(file, type) {
this.$uploadImage('/api/***', file).then(res => {
if (res.code == 1) {
this.$emit('submit',type,res.data.url)
}
})
},
},
}
</script>
<style lang="scss" scoped>
.chatAudio {
.audioPlay{
width: 750rpx;
min-height: 100vh;
position: fixed;
left: 0;
top: 0;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, .8);
text-align: center;
.content{
position: absolute;
left: 0;
bottom: 100rpx;
.gif{
width: 364rpx;
height: 172rpx;
background: #6C9FEB;
border-radius: 32rpx;
margin: auto;
display: flex;
align-items: center;
justify-content: center;
transition: all .5s;
uni-image{
width: 160rpx;
height: 48rpx;
}
}
.red{
background-color: #FB5353;
}
.close{
margin: 176rpx auto 42rpx;
width: 132rpx;
height: 132rpx;
uni-image{
width: 132rpx;
height: 132rpx;
}
}
.bom{
position: relative;
.times{
position: absolute;
left: 50%;
top: 125rpx;
margin-left: -70rpx;
}
uni-image{
width: 750rpx;
height: 254rpx;
margin-top: 26rpx;
}
uni-text{
font-size: 28rpx;
color: #9E9E9E;
}
}
}
}
}
</style>
2.父组件
<template>
<view>
<view class="footer">
<!--
@longpress:长按元素,弹出弹窗。
@touchmove:手指触摸元素后移动,获取手指在屏幕中的位置。
@touchend:手指结束触摸元素,判断是否结束录制音频
-->
<view
@longpress="audioShow = true"
@touchmove.stop.prevent="audioTouchmove"
@touchend.stop.prevent="audioTouchendShow = true">
<text>按住 说话</text>
</view>
</view>
<!--
@submit:通知父组件,发送消息内容。
audioXY:手指在屏幕中的位置信息。
audioShow:是否弹出子组件
audioTouchendShow:是否结束录制
closeAudioShow:子组件通知父组件,结束录制,
-->
<chatAudio
@submit="submit"
:audioXY="audioXY"
:audioShow="audioShow"
:audioTouchendShow="audioTouchendShow"
@closeAudioShow="audioTouchendShow = false,audioShow = false">
</chatAudio>
</view>
</template>
<script>
export default {
data() {
return {
audioShow:false,// 录制音频弹窗
audioTouchendShow:false,// 是否结束录制音频
}
},
methods:{
// 录音长按
audioTouchmove(e){
let x = e.changedTouches[0].clientX;
let y = e.changedTouches[0].clientY;
this.audioXY = {
x:x,
y:y
}
},
// 发送
submit(type,url){
}
}
}
</script>