在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
    });
  })
相关推荐
Jiaberrr2 分钟前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook
顾平安1 小时前
Promise/A+ 规范 - 中文版本
前端
聚名网1 小时前
域名和服务器是什么?域名和服务器是什么关系?
服务器·前端
桃园码工1 小时前
4-Gin HTML 模板渲染 --[Gin 框架入门精讲与实战案例]
前端·html·gin·模板渲染
沈剑心2 小时前
如何在鸿蒙系统上实现「沉浸式」页面?
前端·harmonyos
一棵开花的树,枝芽无限靠近你2 小时前
【PPTist】组件结构设计、主题切换
前端·笔记·学习·编辑器
m0_748237052 小时前
Chrome 关闭自动添加https
前端·chrome
prall2 小时前
实战小技巧:下划线转驼峰篇
前端·typescript
开心工作室_kaic2 小时前
springboot476基于vue篮球联盟管理系统(论文+源码)_kaic
前端·javascript·vue.js
川石教育2 小时前
Vue前端开发-缓存优化
前端·javascript·vue.js·缓存·前端框架·vue·数据缓存