聊天场景在web前端开发中的体验与优化

在日常工作中,如下图的聊天场景是不是很熟悉,没错就是我们再熟悉不过的 QQ 和微信,一个正常的聊天界面大致上是长这个样子的:

聊天场景在web前端开发中的体验与优化

文章插图
 
这种聊天窗口的消息流有两个明显的特点:
  • 最新的消息和滚动条初始位置需要在列表的最底部
  • 下拉加载历史消息要在当前消息列表顶部进行衔接
一般来说要实现这样的功能,对于前端开发来说都不是难事,只要两步就可以了:
  1. 在第一屏消息渲染完之后设置容器的 scrollTop 为一个极大值,这样就把最新消息和滚动条初始位置定位到了最底部;
  2. 当滚动到顶部时渲染第二屏数据,接着设置容器的 scrollTop 为衔接的位置(也就是第二屏的总高度),这样就实现了前后两屏消息的衔接 。
这样的 demo 只需要随手撸二三十行代码就实现了:
聊天场景在web前端开发中的体验与优化

文章插图
 
一开始渲染消息 1~20,滚到顶部后渲染第二屏消息 ABCDEFGHIJK,看上去前后两屏消息的衔接很平滑很流畅 。目前开源社区中也有很多现成的用 React 和 Vue 开发的聊天组件或者示例,他们基本也是用上面提到的思路或者借助 iScroll 实现的 。
用上面这种思路跑在 Web 中是没有任何问题的,但是在小程序中的表现却大失所望,看一下用同样的方式应用到小程序后的实际效果:
聊天场景在web前端开发中的体验与优化

文章插图
 

聊天场景在web前端开发中的体验与优化

文章插图
 
从第一段视频(左)可以看到从列表进入到聊天页面后设置滚动条位置到底部发生了明显的跳动,先看到停留在顶部然后瞬间再去到底部;
第二段视频(右)滚动到顶部加载后,下一屏消息与当前消息的衔接出现了一个明显的跳动,也是先看到在顶部然后才去到预期的位置 。
为什么这个思路在 Web 端体验这么好,到了小程序上体验就如此糟糕呢?原因其实很简单,这是由于小程序底层通信逻辑和视图更新机制造成的:
聊天场景在web前端开发中的体验与优化

文章插图
 
由于小程序跨线程通信和异步更新的特点,内容的渲染和滚动位置的设置无法保证完成的先后顺序,所以必然会先看到上一个位置一闪而过的画面 。
既然是底层的问题,那么这种聊天场景在小程序中难道就玩不了了吗?当然也有尝试过用 opacity 过渡和滚动动画去缓解这种跳动,但都无法从根本上解决这两个体验问题 。
聊天场景在web前端开发中的体验与优化

文章插图
 
当各种常规方案尝试都不尽满意的时候,那就换个思路:从本质上来说,聊天窗口的消息流实际上是一个 “反自然” 的列表,因为在计算机的 “自然界” 和人们习以为常的使用方式上,列表的初始位置都是在最顶部,想要浏览列表更多的内容需要向下滚动,而聊天场景的特点是完全反常规的!
再回到这两个体验问题:为什么需要手动设置最新消息和滚动条到最底部,为什么不让它一开始就在底部?为什么需要要在列表顶部追加数据,为什么不让它在底部追加数据?所以有没有可能颠倒常规,做一个 “反向渲染” 的滚动列表呢?答案是肯定的!
首先像常规的列表一样去渲染,不需要做任何处理,第一条最新消息和滚动条的初始位置是自然地在最上面:
聊天场景在web前端开发中的体验与优化

文章插图
 
然后把整个列表区域的包裹容器用 css 旋转 180°,这样第一条最新消息和滚动条初始位置就在最下面下了:
聊天场景在web前端开发中的体验与优化

文章插图
 
不过此时整个列表是倒置渲染的,最后再把每一条消息组件用同样的方式旋转 180° 使它们显示回正常的视角,这样就实现了一个 “反向渲染” 的列表:
聊天场景在web前端开发中的体验与优化

文章插图
 
虽然是 “反向渲染”,但视觉上和正常的一模一样 。此时顶部就变成了底部,向上追加数据变成了向下追加数据 。最后看一下聊天列表使用 “反向渲染” 之后的体验效果:
聊天场景在web前端开发中的体验与优化


推荐阅读