话不多说,先上效果图
背景
最近在实现一个主动服务的聊天页面,使用的scroll-view
组件实现的,其中有一个需求是,后续进入有聊天内容时,第一次进入需要直接滚动到最底部,在获取聊天记录时发现了一个问题,如果聊天内容中带有图片的话,每次都不能滚动到最底部,还有一个需求是往上滑加载聊天记录,但是在加载聊天记录时由于是在数组的前方插入数据,页面会突然闪动一下,导致数据变成了最新的一条,而不是当前的这一条。在谷歌上搜来搜去,最终看到了一个解决方案反向渲染列表
最初实现方案
使用scroll-into-view属性实现先显示最后一条消息
As we know,在scroll-view
组件有一个scroll-into-view
的属性,该属性的作用是可以让scroll-view
滚动到设置了对应id的元素,于是在拿到这个需求时,就往这个方向考虑,一通操作下来就非常简单的把这个内容实现了(又可以摸鱼咯!)
纯文字的聊天列表是完全没有问题的,但是一旦加上图片就会发现每次都不会滑到最后一条消息,这是为什么呢?
原因是:因为图片渲染需要时间,执行滚动时,图片渲染还没有完成,又没有占位的高度,其实是滚动到了最后一条消息,但是由于在滚动之后才渲染出来,又把高度撑开了,就会给人一种没有滑到最后一条消息的感觉
往聊天列表最前方加数据实现加载历史记录
聊天的列表肯定是会有历史记录的这一个功能,大家刚开始想到的方法都是往这个聊天列表的前方去塞数据实现加载历史记录的功能,这个想法是没问题的,但是由于你是往最前方塞的数据,会导致加载成功后显示的数据不对,并且会有闪动。
这是为什么呢?
原因是:塞入数据之后列表的第一条数据为塞入的最新的一条数据,但是在加载历史记录那个时机其实是显示的是当前最新的那条数据,由于数据发生了更改,就会突然闪动一下,这个时候再用scroll-into-view
来滚动到之前的那条数据,也会发生抖动,交互体验很不好。
解决办法
使用反向渲染列表进行解决
什么是反向渲染列表?
- 首先我们的列表数据不按照最小的在数组第一项,最大的在数组最后一项,我们反过来实现这个数组,让最小的在数组最后一项,最大的数组在第一项
-
使用
transfrom: rotateX(180deg)
去将列表反向展示,然后再使用这个属性对列表里面的每一个元素再反向一次就能将元素内容又反过来 这个时候我们已经实现了列表先展示最后一条消息,你可以往上滑去展示之前的消息,由于我们的最后一条消息其实是数组里面的第一项值,所以在渲染时也是正常的将第一条消息渲染出来,就不会出现还需要去设置属性进行滚动,这样子的效果也是最好的 -
加载历史记录时,由于我们是反向列表,所以只需要往数组的后面塞数据就可以了,往后面塞数据,没有改变之前数据的位置,也不会出现抖动的问题
通过一个简单的css属性,我们就实现了这个反向渲染列表,并且没有多余的一些dom操作和渲染,所达到的性能也是最佳的,至此,我们大功告成!(还没有,接着往下看)
当我以为终于完成了这个工作,可以开心的去交付时,我想了一下,如果初始的数据没有超过scroll-view
的高度会怎么显示呢?
可以看到,如果初始的内容数据小于scroll-view
的高度,由于我们反向渲染了scroll-view
,所以原本应该是底部留白,结果变成了顶部留白,那这种情况怎么办呢?
很简单,只需要将列表中的元素再用一个盒子包裹起来,并且设置他们的高度最小为100%,并且将他们设置flex
布局,用flex-end
来进行排列就可以了
css
{
min-height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
至此,我们真的大功告成了
注意点
由于我们使用了旋转的方法,会导致scroll-view
的scroll-top
和scroll-into-view
都不会按照预期的方式进行,所以如果这儿要实现类似的需求的话,建议自己去进行计算
最后
其实看到这儿可以发现实现这个反向渲染列表是非常的简单,全程只使用了几个css属性就实现了,这是一种思维上的转变,去不同的角度去看待问题,就能更好的去解决问题!