在uniapp中实现即时通讯中的【发送语音】

目录

效果描述

效果展示

代码实现

渲染层

逻辑层


效果描述

在与好友的对话框中,点击语音图标可以切换到给好友发送语音,长按发送语音的按钮即可开始录音:

如果录制时间 小于60s时,松手则表示录音结束并将语音消息发送给对方;

如果录制的时间 超过60s则自动结束,并将语音发送给对方;

如果在录制 60s之内并且没有松手,而是上滑100像素,则表示取消发送该条语音;

效果展示

默认页面 语音消息录制中 取消发送 发送成功

代码实现

发送语音部分的代码是全的,但是别的部分代码有缺失,如果需要对话框页面完整代码的可以私信。

渲染层

html 复制代码
    <view class="guding">
      <view class="bottom" :style="bottomStyle">
        <view class="mic">
          <uv-icon name="mic" color="#09B5BE" size="50rpx" v-if="!isVoice" @click="handleVoice(true)"></uv-icon>
          <image src="../../static/message/keyboard.svg" mode="aspectFill" class="img" v-if="isVoice"
            @click="handleVoice(false)"></image>
        </view>
        <view class="b-cen" v-if="!isVoice">
          <!-- autoHeight:是否自动增加高度,设置auto-height时,height不生效 -->
          <uv-textarea ref="textarea" v-model="msgText" autoHeight border="none" @input="input" :adjustPosition="true"
            @focus="focus" @blur="blur" :showConfirmBar="false" maxlength="100"
            :customStyle="{minHeight:'30rpx',borderRadius:'20rpx'}" :textStyle="{fontSize:'30rpx'}"></uv-textarea>
          <image v-if="isShowSmile" src="../../static/message/smile.svg" mode="aspectFill" class="img"
            @click="handleKeySmile('smile')"></image>
          <image v-if="isShowKeyboard" src="../../static/message/keyboard.svg" mode="aspectFill" class="img"
            @click="handleKeySmile('key')"></image>
        </view>
        <view v-if="isVoice" class="b-cen">
          <view class="bc-text" @touchstart="touchstart" @touchend="touchend" @touchmove="touchmove">按住 说话</view>
        </view>
        <view v-if="!msgText.length" class="mic" @click="handlePlus"><uv-icon name="plus" color="#09B5BE"
            size="50rpx"></uv-icon></view>
        <view class="sendBtn" v-if="msgText.length" @click="handleSubmit">发送</view>
      </view>
      <view class="emoji" v-if="!isShowSmile">
        <text class="e-item" v-for="(item,index) in emojiList" :key="index" @click="handleEmoji(item)">{{item}}</text>
      </view>
      <view class="extra" v-if="isShowExtra">
        <view v-for="item in extraList" :key="item.id" class="ex-item" @click="handleExtra(item)">
          <uv-icon :name="item.icon" size="74rpx"></uv-icon>
          <text>{{item.text}}</text>
        </view>
      </view>
    </view>

逻辑层

javascript 复制代码
  const recorderManager = ref('');
  const isVoice = ref(false) //是否显示语音
  const isshowVoiceBg = ref(false) //是否显示录音背景
  // 切换语音和键盘
  const handleVoice = (val) => {
    isVoice.value = val
    isShowExtra.value = false
    inputh.value = 0
    isShowSmile.value = true
    isShowKeyboard.value = false
    if (val) {
      uni.authorize({
        scope: 'scope.record',
        desc: '需要获取您的录音权限',
        fail(res) {
          uni.showToast({
            title: "请点击右上角"..."功能菜单,进入设置界面,打开麦克风权限后,再重新录音",
            icon: "none",
            duration: 2000,
          });
          return false;
        },
      })
    }
  }
  const pageY = ref(0)
  const timer = ref(0) //计时器
  const vlength = ref(0) //录音时长
  // 点击开始录制语音
  const touchstart = (e) => {
    console.log("开始录制", e)
    let i = 1;
    timer.value = setInterval(() => {
      vlength.value = i;
      i++;
      console.log("计时器开始工作,第几秒", i)
      //结束计时,如果录制时间超过60s就强制停止录音
      if (i > 60) {
        clearInterval(timer.value);
        touchend();
      }
    }, 1000)
    recorderManager.value.start();
    pageY.value = e.changedTouches[0].pageY;
    isshowVoiceBg.value = true
  }
  const isCancel = ref(false)
  const recordSend = ref(true)
  // 结束录音
  const touchend = async (e) => {
    console.log("结束录制", e)
    recorderManager.value.stop();
    clearInterval(timer.value)
    isshowVoiceBg.value = false
    // 如果取消发送录音,则不发送
    if (isCancel.value) {
      recordSend.value = false
    } else {
      recordSend.value = true
    }
    // 结束录音后重置取消状态
    isCancel.value = false
  }
  // 删除录音
  const touchmove = (e) => {
    console.log('删除录音')
    // 如果手指移动距离大于100,则关闭录音界面
    if (pageY.value - e.changedTouches[0].pageY > 100) {
      // 关闭录音界面
      isshowVoiceBg.value = false
      isCancel.value = true
    }
  }
  onMounted(() => {
    recorderManager.value = uni.getRecorderManager()
    // 处理录音停止的逻辑
    recorderManager.value.onStop(async (res) => {
      console.log("录制结束后生成的声音文件", res, vlength.value)
      await http.uploadFile(api.singleUpload, res.tempFilePath).then(res => {
        console.log("录制的时长为多少", vlength.value)
        let data = {
          voice: res.data.filePath,
          time: vlength.value
        };
        if (recordSend.value) {
          sendMsg({ type: 2, message: JSON.stringify(data) }) //语音
        } else {
          uni.showToast({
            icon: "none",
            title: "语音已取消发送"
          })
        }
      })
      // 重置时长和状态
      vlength.value = 0;
      isshowVoiceBg.value = false
    });
  })
相关推荐
烟雨国度28 分钟前
微信小程序和uniapp对比区别
微信小程序·uni-app·notepad++
zbdx不知名菜鸡30 分钟前
Uniapp API
前端·uni-app
魏时烟42 分钟前
小程序echarts不滑动问题
前端·小程序·echarts
GISer_Jing1 小时前
React中useState、useReducer与useRef
前端·javascript·react.js
GISer_Jing1 小时前
React18新特性
前端·javascript·面试
唯余木叶下弦声1 小时前
Python+whisper/vosk实现语音识别
人工智能·whisper·语音识别
不会八股文1 小时前
记录一个Ajax发送JSON数据的坑,后端RequestBody接收参数小细节?JSON对象和JSON字符串的区别?
前端·javascript·ajax
叫卢卡的中国女孩1 小时前
从0到1:如何利用MemFire Cloud快速上线你的应用?
前端·flutter·微信小程序·小程序·serverless
烟雨国度2 小时前
15天项目
前端·javascript·vue.js