第三篇,私有化部署微信的语音电话,视频聊天IM聊天APP开发源码

本文介绍了如何使用uniapp和PHP开发一款包含聊天输入框、消息撤回、音视频通话等功能的IM聊天应用。文章详细讨论了聊天输入框的样式分析、代码逻辑以及上滑取消语音的算法,提供了组件解耦合的设计思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面发布两篇文章,有需要的朋友可以回头看一下,希望可以帮到大家的学习和使用。程序采用了uniapp开发,后端采用PHP,数据库采用MySQL的,程序代码开源,可任意二次开发部署等。

计划实现的功能列表

1、发布消息撤回

2、消息内容可编辑

3、配置项目并实现IM登录

4、会话好友列表的实现

5、聊天输入框的实现

6、聊天界面容器的实现

7、聊天消息项的实现

8、聊天输入框扩展面板的实现

9、聊天会话管理的实现

10、聊天记录的加载与消息收发

11、定位SD配置与收发定位消息

12、贴图表情的定制化开发

13、群功能管理

14、集成音视频通话功能

15、集成仿微信的拍照,相册选择插件

16、集成美颜功能

17、集成TPNS消息推送

18、群功能相关设置

代码区:

聊天输入框的实现

1.样式分析

根据聊天输入框的俩种模式下,我们可以将样式划分为以下2种

①文本模式:

②语音模式:

实际上demo中提供的聊天输入框组件已经覆盖着俩种模式,包括输入文件,发送表情,长按说话,上滑取消等操作。当然如果我们要掌握好这个组件,我们也得分析一下组件中是的代码逻辑。

2. 代码分析

从整体上来说,整个demo工程中将组件进行了解耦合的设计,各个组件文件对应关系如下


由于聊天输入框的组件是ChatInputBox.vue,因此我们着重分析一下该文件中的代码即可。

① data数据结构

data () {
let sysInfo = uni.getSystemInfoSync()
  return {
	ios: sysInfo.platform.toLowerCase() == 'ios',
	pageHeight: sysInfo.windowHeight,
    text: '',
    showText: '',
    focus: false,
    speechMode: false,
    faceMode: false,
    extraMode: false,
    speechIng: false,
    hoverOnSpeechCancelBtn: false
  }
},

从data中的数据结构而言我们不难看出,根据speechMode,faceMode,extraMode切换文本,语音,表情,扩展等操作模式的变化,我们对应的来看一下界面中的代码。

② 界面控制模式切换

在界面中通过speechMode切换显示文本输入框与语音按钮,从而实现语音与文本的切换操作

<image
  @click="clickSpeech"
  class="chat-input-btn is-item"
  :src="!speechMode ? '../static/icon_btn_speech.png'
                    : '../static/icon_btn_keyboard.png'"
></image>
<view v-if="!speechMode"
  :class="[
    'is-item',
    'chat-input-this',
    ios ? '' : 'chat-input-this-isAndroid'
  ].join(' ')"
>
  <textarea
    ref="input"
    class="chat-input-this-elem"
    :value="showText"
    :focus="focus"
    :autofocus="focus"
    @blur="focus = false"
    @touchend="onInputFocus"
    @input="onTextareaInput"
    :adjust-position="false"
    auto-height
  />
</view>
<view
  v-else
  @touchstart.prevent="touchOnSpeech"
  @touchend="touchOffSpeech"
  @touchmove="touchMoveSpeech"
  class="is-item chat-input-this chat-input-speech-btn"
>
  <text class="chat-input-speech-btn-inner">按住说话</text>
</view>
<image
  class="chat-input-btn is-item"
  src="../static/icon_btn_face.png"
  @click="clickFaceBtn"
></image>
<image
  v-if="!text"
  class="chat-input-btn is-item"
  src="../static/icon_btn_more.png"
  @click="clickExtra"
></image>
<text
  v-else
  class="chat-send-btn is-item"
  @click="clickSend"
>发送</text>
</view>

③ 语音聊天的覆盖层实现

比较特别的地方是语音聊天有一个“说话中”的覆盖层,我们通过在template的最后追加一个语音聊天覆盖层,通过监听speechMode是否为true控制显隐,从而实现语音聊天的效果

<view v-if="speechIng" class="speech-fixed">
 <view></view>
 <view
   class="speech-fixed__time"
 >
   <image
     class="speech-fixed__time-icon"
     :src="
       hoverOnSpeechCancelBtn ? '/static/icon_cancel_record.png'
                              : '/static/recording.gif'
     "
     mode="widthFix"
   ></image>
   <text
     class="speech-fixed__time-text"
   >{{ hoverOnSpeechCancelBtn ? '手指上滑 取消发送'
                              : (speechIng.time > 50000 ? `剩余 ${60 - (speechIng.time / 1000).toFixed(0)} 秒` : '松开手指 取消发送') }}</text>
 </view>
 <view></view>
</view>

3. 上滑取消语音的算法

一般而言用户在长按说话的时候,很难去做点击取消按钮这类操作,因此对于取消语音一般采用的是上滑取消语音的操作,而对于组件而言,内部实现长按时候手指移动算法如下
首先我们需要在界面上监听触摸事件,该事件的监听在vue/nvue下都能得到一个统一的反馈,只是nvue下对于y轴的坐标计算需要做一个负值纠正的处理。

<view
        @touchstart.prevent="touchOnSpeech"
        @touchend="touchOffSpeech"
        @touchmove="touchMoveSpeech"
        class="is-item chat-input-this chat-input-speech-btn"
      >
        <text class="chat-input-speech-btn-inner">按住说话</text>
      </view>

touchOnSpeech主要是记录当前为长按事件,做好其他UI控件的事件冲突处理,也标记开始录音。

async touchOnSpeech () {
        this.speechIng = { time: 0, timer: null }
        this.speechIng.timer = setInterval(e => {
          this.speechIng && (this.speechIng.time += 500);
          // 这里是超时判断
          if (this.speechIng.time >= 60000) {
            this.hoverOnSpeechCancelBtn = false
            this.touchOffSpeech()
          }
        }, 500)
        console.log('speech-start')
        let success = await this.$imUtils.startRecord()
        if (!success) {
          this.touchOffSpeech()
          uni.showToast({
            icon: 'none',
            position: 'bottom',
            title: '录音失败,请检查是否授权麦克风权限'
          })
        }
      }

touchOffSpeech主要是记录当前松开长按事件,从而做结束/取消录音的判断,这里使用了来自lodash的防抖处理,因为nvue下有可能会多次触发

touchOffSpeech: _.debounce(async function () {
        if (!this.speechIng) {
          return
        }
        clearInterval(this.speechIng.timer)
        let timeLen = this.speechIng.time
        this.speechIng = null
        if (this.hoverOnSpeechCancelBtn) {
          this.hoverOnSpeechCancelBtn = false
          return
        }
        if (timeLen < 1000) {
          return
        }
        let filePath = await this.$imUtils.endRecord()
        if (!filePath) {
          return
        }
        this.$emit('sendAudio', { filePath, timeLen })
      }, 500, { leading: true, trailing: false }),

touchMoveSpeech主要是计算当前手指移动位置,如果到达了取消区域则设置取消状态为true,从而实现取消语音的处理。

touches = touches[0]
        let minScope = 0
        let maxScope = this.pageHeight - 50
        // 这里我们默认只要离开了【长按说话】按钮就属于取消语音的处理,开发者可以根据实际需求调整业务逻辑
        if (touches.screenY >= minScope && touches.screenY <= maxScope) {
          this.hoverOnSpeechCancelBtn = true
        } else {
          this.hoverOnSpeechCancelBtn = false
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值