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

时间:2024-10-14 07:19:07

前面发布两篇文章,有需要的朋友可以回头看一下,希望可以帮到大家的学习和使用。程序采用了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工程中将组件进行了解耦合的设计,各个组件文件对应关系如下


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

① data数据结构

  1. data () {
  2. let sysInfo = ()
  3. return {
  4. ios: () == 'ios',
  5. pageHeight: ,
  6. text: '',
  7. showText: '',
  8. focus: false,
  9. speechMode: false,
  10. faceMode: false,
  11. extraMode: false,
  12. speechIng: false,
  13. hoverOnSpeechCancelBtn: false
  14. }
  15. },

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

② 界面控制模式切换

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

  1. <image
  2. @click="clickSpeech"
  3. class="chat-input-btn is-item"
  4. :src="!speechMode ? '../static/icon_btn_speech.png'
  5. : '../static/icon_btn_keyboard.png'"
  6. ></image>
  7. <view v-if="!speechMode"
  8. :class="[
  9. 'is-item',
  10. 'chat-input-this',
  11. ios ? '' : 'chat-input-this-isAndroid'
  12. ].join(' ')"
  13. >
  14. <textarea
  15. ref="input"
  16. class="chat-input-this-elem"
  17. :value="showText"
  18. :focus="focus"
  19. :autofocus="focus"
  20. @blur="focus = false"
  21. @touchend="onInputFocus"
  22. @input="onTextareaInput"
  23. :adjust-position="false"
  24. auto-height
  25. />
  26. </view>
  27. <view
  28. v-else
  29. @="touchOnSpeech"
  30. @touchend="touchOffSpeech"
  31. @touchmove="touchMoveSpeech"
  32. class="is-item chat-input-this chat-input-speech-btn"
  33. >
  34. <text class="chat-input-speech-btn-inner">按住说话</text>
  35. </view>
  36. <image
  37. class="chat-input-btn is-item"
  38. src="../static/icon_btn_face.png"
  39. @click="clickFaceBtn"
  40. ></image>
  41. <image
  42. v-if="!text"
  43. class="chat-input-btn is-item"
  44. src="../static/icon_btn_more.png"
  45. @click="clickExtra"
  46. ></image>
  47. <text
  48. v-else
  49. class="chat-send-btn is-item"
  50. @click="clickSend"
  51. >发送</text>
  52. </view>

③ 语音聊天的覆盖层实现

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

  1. <view v-if="speechIng" class="speech-fixed">
  2. <view></view>
  3. <view
  4. class="speech-fixed__time"
  5. >
  6. <image
  7. class="speech-fixed__time-icon"
  8. :src="
  9. hoverOnSpeechCancelBtn ? '/static/icon_cancel_record.png'
  10. : '/static/'
  11. "
  12. mode="widthFix"
  13. ></image>
  14. <text
  15. class="speech-fixed__time-text"
  16. >{{ hoverOnSpeechCancelBtn ? '手指上滑 取消发送'
  17. : (speechIng.time > 50000 ? `剩余 ${60 - (speechIng.time / 1000).toFixed(0)} 秒` : '松开手指 取消发送') }}</text>
  18. </view>
  19. <view></view>
  20. </view>

3. 上滑取消语音的算法

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

  1. <view
  2. @="touchOnSpeech"
  3. @touchend="touchOffSpeech"
  4. @touchmove="touchMoveSpeech"
  5. class="is-item chat-input-this chat-input-speech-btn"
  6. >
  7. <text class="chat-input-speech-btn-inner">按住说话</text>
  8. </view>

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

  1. async touchOnSpeech () {
  2. = { time: 0, timer: null }
  3. = setInterval(e => {
  4. && (.time += 500);
  5. // 这里是超时判断
  6. if (.time >= 60000) {
  7. = false
  8. ()
  9. }
  10. }, 500)
  11. ('speech-start')
  12. let success = await this.$()
  13. if (!success) {
  14. ()
  15. ({
  16. icon: 'none',
  17. position: 'bottom',
  18. title: '录音失败,请检查是否授权麦克风权限'
  19. })
  20. }
  21. }

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

  1. touchOffSpeech: _.debounce(async function () {
  2. if (!this.speechIng) {
  3. return
  4. }
  5. clearInterval(this.)
  6. let timeLen = this.
  7. this.speechIng = null
  8. if (this.hoverOnSpeechCancelBtn) {
  9. this.hoverOnSpeechCancelBtn = false
  10. return
  11. }
  12. if (timeLen < 1000) {
  13. return
  14. }
  15. let filePath = await this.$()
  16. if (!filePath) {
  17. return
  18. }
  19. this.$emit('sendAudio', { filePath, timeLen })
  20. }, 500, { leading: true, trailing: false }),

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

  1. touches = touches[0]
  2. let minScope = 0
  3. let maxScope = - 50
  4. // 这里我们默认只要离开了【长按说话】按钮就属于取消语音的处理,开发者可以根据实际需求调整业务逻辑
  5. if ( >= minScope && <= maxScope) {
  6. = true
  7. } else {
  8. = false
  9. }