文章概述

上一次咱们探讨过聊天输入框的实现,实现文本,语音,标签的编辑发送,而本次咱们的关注点将回归到整个聊天界面容器的实现。


聊天界面容器的实现

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