文章概述
上一次咱们探讨过聊天输入框的实现,实现文本,语音,标签的编辑发送,而本次咱们的关注点将回归到整个聊天界面容器的实现。
聊天界面容器的实现
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)
},
我的项目开源地址及交换群
我的项目成品成果查看:我的项目引言
我的项目开源地址:https://gitee.com/ckong/Zhimi…
Uniapp 开发交换群:755910061