在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
    });
  })
相关推荐
水银嘻嘻6 小时前
12 web 自动化之基于关键字+数据驱动-反射自动化框架搭建
运维·前端·自动化
小嘟嚷ovo6 小时前
h5,原生html,echarts关系网实现
前端·html·echarts
十一吖i7 小时前
Vue3项目使用ElDrawer后select方法不生效
前端
只可远观7 小时前
Flutter目录结构介绍、入口、Widget、Center组件、Text组件、MaterialApp组件、Scaffold组件
前端·flutter
周胡杰7 小时前
组件导航 (HMRouter)+flutter项目搭建-混合开发+分栏效果
前端·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
敲代码的小吉米7 小时前
前端上传el-upload、原生input本地文件pdf格式(纯前端预览本地文件不走后端接口)
前端·javascript·pdf·状态模式
是千千千熠啊7 小时前
vue使用Fabric和pdfjs完成合同签章及批注
前端·vue.js
九月TTS8 小时前
TTS-Web-Vue系列:组件逻辑分离与模块化重构
前端·vue.js·重构
我是大头鸟8 小时前
SpringMVC 内容协商处理
前端
Humbunklung8 小时前
Visual Studio 2022 中添加“高级保存选项”及解决编码问题
前端·c++·webview·visual studio