五、Uniapp+vue+騰訊IM+騰訊音視頻開發仿微信的IM聊天APP,支持各類消息收發,音視頻通話,附vue實現源碼(已開源)-聊天輸入框的實現

會話好友列表的實現

1、項目引言
2、騰訊雲後台配置TXIM
3、配置項目並實現IM登錄
4、會話好友列表的實現
5、聊天輸入框的實現
6、聊天界面容器的實現
7、聊天消息項的實現
8、聊天輸入框擴展面板的實現
9、聊天會話管理的實現
10、聊天記錄的加載與消息收發
11、定位SD配置與收發定位消息
12、貼圖表情的定製化開發
13、騰訊雲後台配置TRTC功能
14、集成音視頻通話功能
15、集成仿微信的拍照,相冊選擇插件
16、集成美顏功能
17、集成TPNS消息推送(暫未接入)


@


文章概述

今天的文章比較貼合界面設計部分,在demo中我們已經實現了一個業務組件——聊天輸入框,那麼本文將教大家聊天輸入框的業務實現以及如何修改調整聊天輸入框


聊天輸入框的實現

1.樣式分析

根據聊天輸入框的倆種模式下,我們可以將樣式劃分為以下2種

  1. 文本模式:
    在這裡插入圖片描述

  2. 語音模式:
    在這裡插入圖片描述

實際上demo中提供的聊天輸入框組件已經覆蓋著倆種模式,包括輸入文件,發送表情,長按說話,上滑取消等操作。當然如果我們要掌握好這個組件,我們也得分析一下組件中是的代碼邏輯。

2. 代碼分析

從整體上來說,整個demo工程中將組件進行了解耦合的設計,各個組件文件對應關係如下
在這裡插入圖片描述
由於聊天輸入框的組件是ChatInputBox.vue,因此我們着重分析一下該文件中的代碼即可。

1. 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切換文本,語音,表情,擴展等操作模式的變化,我們對應的來看一下界面中的代碼。

2. 界面控制模式切換

在界面中通過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>

3. 語音聊天的覆蓋層實現

比較特別的地方是語音聊天有一個「說話中」的覆蓋層,我們通過在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>

2.上滑取消語音的算法

一般而言用戶在長按說話的時候,很難去做點擊取消按鈕這類操作,因此對於取消語音一般採用的是上滑取消語音的操作,而對於組件而言,內部實現長按時候手指移動算法如下
首先我們需要在界面上監聽觸摸事件,該事件的監聽在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
}

項目開源地址及交流群

項目開源地址://gitee.com/ckong/Zhimi.OpenSource.UniApp.TXIM.Vue
Uniapp開發交流群:755910061