文章概述
整个IM我的项目的关键点来了,本文将讨论一下聊天音讯的实现,如何收发音讯并且实现聊天音讯的UI显示。
聊天音讯项的实现
1.收发聊天音讯
1.1 接管聊天音讯
接管聊天音讯显得很简略,在之前的会话列表实现中曾经做过一次,这次咱们代码其实差不多,惟一不一样的是承受后咱们须要做筛选确定须要回显到聊天音讯界面的我的项目。
绑定音讯事件局部的代码如下:
// 这里抉择在onLoad绑定,确定不会漏接数据async onLoad (params) { // 做好一个变量确定我当初在和谁聊天 this.receiver = params.receiver // 监听新的音讯 this.$txim.$on('onRecvC2CTextMessage', this.onRecvMessageHanlder) this.$txim.$on('onRecvC2CCustomMessage', this.onRecvMessageHanlder) this.$txim.$on('onRecvGroupTextMessage', this.onRecvMessageHanlder) this.$txim.$on('onRecvGroupCustomMessage', this.onRecvMessageHanlder) this.$txim.$on('onRecvNewMessage', this.onRecvMessageHanlder)}
接管到音讯的回调事件处理如下
// 获取音讯 async onRecvMessageHanlder ({ data }) { let V2TIMMessageManager = this.$txim.getMessageManager() let senderId = data?.sender?.userID || data?.sender if (senderId == this.receiver) { this.HistoryMessageToChatLog([data]) this.$txim.markC2CMessageAsRead(senderId) await this.$nextTick() this.$refs.chatLayout.scrollToBottom() } },
1.2 发送聊天音讯
发送聊天音讯实际上demo曾经有所封装了,对于文本音讯而言发送的代码如下:
// 发送文字 这里须要防抖解决,反正屡次点击发送按钮从而呈现问题sendText: _.debounce(async function (text) { let V2TIMMessageManager = this.$txim.getMessageManager() // 创立音讯构造体 let v2TIMMessage = V2TIMMessageManager.createTextMessage(text) try { // 发送音讯 let ret = await V2TIMMessageManager.sendMessage(v2TIMMessage, this.receiver) // 更新聊天音讯 this.HistoryMessageToChatLog([ret.data]) } catch (e) { this.$utils.toast('发送失败') } await this.$nextTick() // 放弃滚动到底部 this.$refs.chatLayout.scrollToBottom()}, 500, { leading: true, trailing: false }),
下面演示的是文本音讯,而对于其余音讯而言,只是创立的音讯构造体不一样,各种音讯的构造体如下
// 文本let v2TIMMessage = V2TIMMessageManager.createTextMessage(text)// 大表情let v2TIMMessage = V2TIMMessageManager.createFaceMessage(0, { faceUrl: url })// 图片let v2TIMMessage = V2TIMMessageManager.createImageMessage(filePath)// 视频let v2TIMMessage = V2TIMMessageManager.createVideoMessage(filePath, 'mp4', timeLen, snapshotPath)// 语音let v2TIMMessage = V2TIMMessageManager.createSoundMessage(filePath, timeLen)// 定位let v2TIMMessage = V2TIMMessageManager.createLocationMessage(address, longitude, latitude)
2.聊天音讯格式化
为了做好组件之间的解耦合,咱们须要将腾讯音讯的构造体进行格式化,映射为咱们音讯组件中能辨认的构造体,映射局部的代码实际上utils/imUtils文件中曾经有所提供了,具体的操作如下(这里须要留神,外面依据了音讯记录的elemType做了判断,elemType腾讯TXIM的官网文档对应这里https://im.sdk.qcloud.com/doc/zh-cn/classcom_1_1tencent_1_1imsdk_1_1v2_1_1V2TIMMessageManager.html)
async HistoryMessageToChatLog (msgLogs, unshift) { for (let item of msgLogs) { let msgType = [ null, this.$imUtils.MSG_TEXT, null, this.$imUtils.MSG_IMAGE, this.$imUtils.MSG_AUDIO, this.$imUtils.MSG_VIDEO, null, this.$imUtils.MSG_LOCATION, this.$imUtils.MSG_TIP_FACE, ][item.elemType] let dataJson = { id: item.msgID, head: '../static/icon_u_head.jpg', self: item.isSelf, type: msgType, data: null } switch (msgType) { case this.$imUtils.MSG_TEXT: dataJson.data = this.$imUtils.buildMessageItem(msgType, item.elem.text, item) break case this.$imUtils.MSG_LOCATION: dataJson.data = this.$imUtils.buildMessageItem(msgType, item, item.elem.latitude, item.elem.longitude, item.elem.desc, item) break case this.$imUtils.MSG_IMAGE: dataJson.data = this.$imUtils.buildMessageItem(msgType, item.elem.imageList[0].url, item) break case this.$imUtils.MSG_AUDIO: dataJson.data = this.$imUtils.buildMessageItem(msgType, '', item.elem.duration * 1000, item) break case this.$imUtils.MSG_VIDEO: dataJson.data = this.$imUtils.buildMessageItem(msgType, item, item) break case this.$imUtils.MSG_TIP_FACE: dataJson.data = this.$imUtils.buildMessageItem(msgType, item, item) break default: // console.log(item) } if (msgType) { this.chatLogs[unshift ? 'unshift' : 'push'](dataJson) } }}
3.聊天音讯回显
聊天音讯局部demo曾经内置了一个聊天组件,咱们能够实现开箱即用,只须要引入组件定义好list即可
首先咱们须要引入组件,并且在template对应的地位写好即可
<chat-message-item v-for="item in chatLogs" :ref="item.id" :self="item.self" :head="item.head" :type="item.type" :data="item.data" :prevent="currentPopItem && currentPopItem.item.id == item.id" @longpressContent="currentPopItem = { ref: $refs[item.id][0], item }"></chat-message-item>
<script>import ChatMessageItem from '../components/ChatMessageItem'export default { components: { ChatMessageItem },}</script>
4.聊天音讯弹出菜单
一般而言咱们聊天音讯还须要有一些操作,比方删除,转发之类的,那么咱们也须要为聊天音讯减少弹出菜单,这须要咱们去做浮动地位的计算,然而demo中曾经提供了一个弹出菜单,使得咱们能够很简略的实现这个性能。
聊天音讯的弹出菜单组件在componetns/ChatMsgItemProp下,开发者须要本人批改成为本人须要的性能,这里咱们先引入组件而后退出到template中对应地位
<chat-layout class="page" ref="chatLayout" :end="end" @upperLoading="loadMoreLog" @scroll="onChatLayoutScroll" @clickRoot="onRootClick"> <chat-message-item v-for="item in chatLogs" :ref="item.id" :self="item.self" :head="item.head" :type="item.type" :data="item.data" :prevent="currentPopItem && currentPopItem.item.id == item.id" @longpressContent="currentPopItem = { ref: $refs[item.id][0], item }" > </chat-message-item> <!-- 这里要显著留神,弹出不是在ChatMessageItem外面的! --> <chat-msg-item-pop :show="currentPopItem" @clickFn="onPopClickFn($event)" ></chat-msg-item-pop></chat-layout>
这里咱们次要是从chatMessageItem中获取到了长按事件的坐标信息,而后交给chatMsgItemPop,弹出组件会依据坐标计算确定显示地位和方向,计算局部的算法如下:
calcPopPosition () { let { ref } = this.show let el = ref.$el let pop = this.$refs.pop let content = el.children[2] dom.getComponentRect(pop, ({ size }) => { let popSize = size dom.getComponentRect(content, ({ size }) => { let contentSize = size this.popPoint.reverse = (contentSize.top - popSize.height) < 0 this.popPoint.popHeight = popSize.height this.popPoint.itemHeight = contentSize.height this.popPoint.touchX = contentSize.left + contentSize.width / 2 this.popPoint.touchY = contentSize.top }) })}
通过计算确定了显示地位之后就会显示性能菜单列表,在组件中内置了以下的按钮图标,性能暂未实现,开发者能够本人依据理论须要定制化解决哦。
{ type: 'copy', label: '复制', icon: '/static/icon_copy.png' }, { type: 'share', label: '转发', icon: '/static/icon_share.png' }, { type: 'collect', label: '珍藏', icon: '/static/icon_collect.png' }, { type: 'delete', label: '删除', icon: '/static/icon_delete.png' }, { type: 'ref', label: '援用', icon: '/static/icon_ref_msg.png' }, { type: 'translate', label: '翻译', icon: '/static/icon_fanyi.png' }, { type: 'search', label: '搜一搜', icon: '/static/icon_search_fun.png' },
我的项目开源地址及交换群
我的项目成品成果查看:请点击我的项目引言
我的项目开源地址:https://gitee.com/ckong/Zhimi...
Uniapp开发交换群:755910061