六、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消息推送(暫未接入)
@
文章概述
上一次我們討論過聊天輸入框的實現,實現文本,語音,標籤的編輯發送,而本次我們的關注點將回歸到整個聊天介面容器的實現。
聊天介面容器的實現
1.為什麼要實現一個聊天介面容器
一般情況下,開發者會採用直接在對應的介面中實現聊天介面UI的方式做開發。這種開發思路無可厚非,但是如果我們要實現跨平台的聊天IM,那麼我們不免要遇到組件之間的事件衝突,多平台表現差距的問題,特別是在聊天中我們還需要實現滾動載入。如果說我們在每個介面都實現了一套程式碼,那麼會導致整體程式碼的可維護性下降,因此我們有必要實現一個聊天介面容器,將消息顯示,滾動載入,長按菜單,輸入,編輯等都在這裡面做好兼容處理,使得介面和業務組件實現解耦合。
2. 聊天介面容器的設計
聊天介面容器的設計很簡單,我們大概整理一下需要實現以下幾點功能。
- 滾動到底部
- 輸入法高度自適應
- 滾動載入
2.1 滾動到底部
首先我們需要明確我們的聊天介面肯定是需要滾動的,並且在接收/發送消息的時候我們需要滾動在最底部,類似微信收發消息的效果,組件我們肯定只有scrollView可以使用,具體實現如下
<scroll-view
ref="scroll"
class="chat-layout__scroll"
:style="{
height: scrollBoxHeight
}"
:scroll-y="!inUpperLoading"
:upper-threshold="0"
:show-scrollbar="false"
:scroll-top="scrollTop"
@scrolltoupper="onScrollToUpper"
@click="onScrollClick"
@scroll="onScroll"
>
<text
v-if="inUpperLoading && !end"
class="chat-layout__scroll-loading"
>
</text>
<slot></slot>
<view ref="ending"></view>
</scroll-view>
實現滾動到底部,一般而言是只能使用scrollTop,而這樣為了兼容nvue,我們採用weex原生的dom模組獲取可滾動高度 – 容器高度就可以實現可滾動高度。
async scrollToBottom (retouchCount) {
if (this.inUpperLoading || this.scrollBottoming) {
return
}
this.scrollBottoming = true
// await this.$nextTick()
// this.$utils.delay(100)
// let view = await this.$utils.query(this, '.chat-layout__scroll')
// this.scrollTop = view.scrollHeight
// nvue必須使用下面這種
await this.$nextTick()
dom.scrollToElement(this.$refs.ending, { animated: false })
this.scrollBottoming = false
await this.$nextTick()
retouchCount = retouchCount || 0
retouchCount++
// 最多5次重新滾動到底部的測試, nvue下面的渲染並且是nextTick之後就百分百正常
dom.getComponentRect(this.$refs.scroll, ({ size }) => {
let { detail } = this.scrollEvent
if (!detail) {
this.scrollTop = 0
if (retouchCount < 5) {
this.scrollToBottom(retouchCount)
}
} else {
this.scrollTop = detail.scrollHeight - size.height
// console.log('重新定位scrollTop')
if (retouchCount < 5) {
this.scrollToBottom(retouchCount)
}
}
})
}
2.2輸入法高度自適應
一般情況下在vue介面,我們input focus之後是會自動適應輸入法高度,然而在nvue中,當我們介面中嵌套了影片播放器之類的,會導致input高度計算錯誤,因此我們需要手動監聽輸入法高度變化,然後做一個適應性的收縮介面容器即可。
<view
class="chat-layout"
:style="{
paddingBottom: paddingBottomHeight
}"
>
</view>
uni.onKeyboardHeightChange(this.onKeyboardHeightChange)
// methods中
async onKeyboardHeightChange ({ height }) {
this.paddingBottomHeight = height
await this.$nextTick()
height && this.scrollToBottom()
},
2.3滾動載入
滾動載入有很多方式實現,這裡我們只簡易的實現了一個,監聽scrollView的scrolltoupper事件確定是否載入,然後我們拋出給業務層控制滾動載入。
<scroll-view
ref="scroll"
class="chat-layout__scroll"
:style="{
height: scrollBoxHeight
}"
:scroll-y="!inUpperLoading"
:upper-threshold="0"
:show-scrollbar="false"
:scroll-top="scrollTop"
@scrolltoupper="onScrollToUpper"
@click="onScrollClick"
@scroll="onScroll"
>
onScrollToUpper: throttle(async function() {
if (this.inUpperLoading || this.disableUpperLoading || this.end) {
return
}
this.inUpperLoading = true
let oldChildrens = this.$refs.scroll.children.length
this.$emit('upperLoading', async isEnd => {
if (isEnd) {
this.disableUpperLoading = true
}
await this.$nextTick()
let newChildrens = this.$refs.scroll.children.length
this.inUpperLoading = false
let refEl = this.$refs.scroll.children[newChildrens - oldChildrens]
dom.scrollToElement(refEl, { animated: false })
})
}, 200, {
leading: true,
trailing: false
}),
而對於業務層來說,接收到upperLoading事件之後做數據載入,然後回饋載入完成即可
async loadMoreLog (next) {
console.log('loadMoreLog')
await this.getLogs(this.screenLogLen)
await this.$nextTick()
next(false)
},
項目開源地址及交流群
項目開源地址://gitee.com/ckong/Zhimi.OpenSource.UniApp.TXIM.Vue
Uniapp開發交流群:755910061