前面发布两篇文章,有需要的朋友可以回头看一下,希望可以帮到大家的学习和使用。程序采用了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数据结构
-
data () {
-
let sysInfo = ()
-
return {
-
ios: () == 'ios',
-
pageHeight: ,
-
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
-
@="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/'
-
"
-
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
-
@="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 () {
-
= { time: 0, timer: null }
-
= setInterval(e => {
-
&& (.time += 500);
-
// 这里是超时判断
-
if (.time >= 60000) {
-
= false
-
()
-
}
-
}, 500)
-
('speech-start')
-
let success = await this.$()
-
if (!success) {
-
()
-
({
-
icon: 'none',
-
position: 'bottom',
-
title: '录音失败,请检查是否授权麦克风权限'
-
})
-
}
-
}
touchOffSpeech主要是记录当前松开长按事件,从而做结束/取消录音的判断,这里使用了来自lodash的防抖处理,因为nvue下有可能会多次触发
-
touchOffSpeech: _.debounce(async function () {
-
if (!this.speechIng) {
-
return
-
}
-
clearInterval(this.)
-
let timeLen = this.
-
this.speechIng = null
-
if (this.hoverOnSpeechCancelBtn) {
-
this.hoverOnSpeechCancelBtn = false
-
return
-
}
-
if (timeLen < 1000) {
-
return
-
}
-
let filePath = await this.$()
-
if (!filePath) {
-
return
-
}
-
this.$emit('sendAudio', { filePath, timeLen })
-
}, 500, { leading: true, trailing: false }),
touchMoveSpeech主要是计算当前手指移动位置,如果到达了取消区域则设置取消状态为true,从而实现取消语音的处理。
-
touches = touches[0]
-
let minScope = 0
-
let maxScope = - 50
-
// 这里我们默认只要离开了【长按说话】按钮就属于取消语音的处理,开发者可以根据实际需求调整业务逻辑
-
if ( >= minScope && <= maxScope) {
-
= true
-
} else {
-
= false
-
}