评论

非常简单的长列表(无限上拉触底加载 onReachBottom)实现方案

非常简单的长列表(无限上拉触底加载 onReachBottom)实现方案

我们知道小程序针对长列表有两个硬杠杠,一旦越界直接给白屏:

1、setData的数组数据不能超过1M。

2、DOM数不能太多,具体数据未知。

官方这样处理也不无道理,太长了本身性能确实也有问题。所以长列表一定要人为干预处理,不处理一直上拉加载肯定是不行的。

目前主流的处理方法有三种:

1、二维数组,就是把数据改为二维的,每一个分页数据作为一个一维数组的元素。这样处理,只解决了setData的问题,DOM的问题并未解决。并且把本来是一维的数据强行二维化,在很多逻辑处理上变得复杂。

2、官方提供了一个扩展组件recycle-view,但它要求item等高,存在局限性https://developers.weixin.qq.com/miniprogram/dev/extended/component-plus/recycle-view.html

3、自行搭建骨架屏,类似于方案2的自研版本,根据自己的实际需要编写代码。实现成本非常高。

实现方案如下(太简单了,不提供代码示例):

1、思路:只保留最新的n页数据进行setData,每新加载一页数据,就舍弃最前面一页的数据。同时把第1页的数据保存起来,监听onPageScroll,如果发现用户拉回到了页面顶部,则舍弃所有数据,把第1页的数据setData回来。

2、举个例子:假设n=5,那么当加载了第6页数据时,第6页数据合并到数组尾部,把数组头部的第1页数据去掉,让setData的数据始终保持5页。这里有个细节要处理好,就是去除数据的时候先setData一次,新数据加载合并后,再setData一次,这样可以保证用户的scrollTop不会走位,停留在最新一条数据那个位置。

3、这个方案也存在一些弊端,看你实际项目中能否接受,主要有两个问题:a、用户如果倒着往回逐条浏览,体验是不连续的,因为中间一段我们已经舍弃掉了,如果拉到页面顶部时,将会出现直接回到第一条数据。b、去除数据的setData操作时,存在一定程度的闪屏现象。(针对问题a,应该可以解决,无非就是把数据再逐页塞回来,而不是像我的方案简单粗暴的回到第一页数据,如果项目有需要可以自行尝试。)

4、适用范围:比较适合信息处理类应用,比如后台管理系统。这类应用,往往头几屏内容就能找到信息,或者借助搜索,比较少会拉很多屏。而且往往处理完毕时是直接回到顶部的,不会逐条翻回去。所以这类应用只要保证不出白屏,一些小概率场景下存在一些几乎可以忽略的体验小瑕疵可以接受。信息浏览类应用,比如新闻应用,往往都是长列表浏览,小瑕疵就不一定能接受。

最后一次编辑于  2020-10-28  
点赞 0
收藏
评论

2 个评论

  • 毅醉听雨眠
    毅醉听雨眠
    2020-10-28

    其实可以监听当前在第几页,然后只渲染n-2和n+2的数据,其他隐藏为带高度的空dom,页面销毁的时候就删了监听

    2020-10-28
    赞同 1
    回复 8
    • 郑旭东
      郑旭东
      2020-10-28
      问题在于,监听的是页面高度,和数据并不能完全对应起来。尤其是item不等高的情况
      2020-10-28
      回复
    • 毅醉听雨眠
      毅醉听雨眠
      2020-10-28回复郑旭东
      不等高没事的,有个接口可以监听到特定id的dom的长度,不用设置item的高 createIntersectionObserver
      2020-10-28
      回复
    • 毅醉听雨眠
      毅醉听雨眠
      2020-10-28回复郑旭东
      而且当前屏幕显示的dom的id改变,马上就可以监听到
      2020-10-28
      回复
    • 郑旭东
      郑旭东
      2020-10-28
      没仔细研究过哈,或许也是个不错的方案。要平滑处理当前几屏的几个item显示隐藏,逻辑处理肯定比目前的方案复杂,但是处理得好,效果还不错。你这个其实是我说的方案3的具体实现方法之一。
      2020-10-28
      回复
    • 毅醉听雨眠
      毅醉听雨眠
      2020-10-28回复郑旭东
      我也是昨天才试验成功的,感觉效果还不错
      2020-10-28
      回复
    查看更多(3)
  • admin
    admin
    2020-07-25

    uniapp上发现的这个,貌似还不错

    data: {  
        listData: []  
    },  
    onReachBottom() { //上拉加载  
        // 通过长度获取下一次渲染的索引  
        let index = this.data.listData.length;  
        let newData = {}; //新变更数据  
        Api.getNews().forEach((item) => {  
            newData['listData[' + (index++) + ']'] = item //赋值,索引递增  
        })   
        this.setData(newData) //增量数据,发送数据到视图层  
    }
    



    2020-07-25
    赞同
    回复 3
    • 郑旭东
      郑旭东
      发表于小程序端
      2020-07-26
      这个就是二维数组方案,不能解决DOM数量超出的问题
      2020-07-26
      回复
    • admin
      admin
      2020-07-26回复郑旭东
      那目前没有别的方法了吗?闪屏不能接受
      2020-07-26
      回复
    • 郑旭东
      郑旭东
      2020-07-29回复admin
      有,方案3呀。闪屏不是很明显,看实际项目需求评判。
      2020-07-29
      回复
登录 后发表内容