美文网首页
六、Uniapp+vue+腾讯IM+腾讯音视频开发仿微信的IM聊

六、Uniapp+vue+腾讯IM+腾讯音视频开发仿微信的IM聊

作者: 智密科技 | 来源:发表于2022-01-10 23:07 被阅读0次

文章概述

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


聊天界面容器的实现

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.OpenSource.UniApp.TXIM.Vue

Uniapp开发交流群:755910061

相关文章

网友评论

      本文标题:六、Uniapp+vue+腾讯IM+腾讯音视频开发仿微信的IM聊

      本文链接:https://www.haomeiwen.com/subject/hvvvcrtx.html