likes
comments
collection
share

小程序动态高度长列表优化实战:解决滑动白屏与性能问题(二)

作者站长头像
站长
· 阅读数 56

前言

本案例将涉及一个不完全动态高度的长列表问题。所谓的不完全动态,是指每个列表项的高度虽然不完全相同,但我们可以通过计算得到每个列表项的实际高度。列表项的高度可以根据后台返回的数据计算得出。为了实现这个功能,我们将对 taro 框架的 virtual-list 组件进行改造。

案例 · 小程序长列表点击响应延时

小程序动态高度长列表优化实战:解决滑动白屏与性能问题(二)

在应用的使用过程中,我们发现,随着列表项的不断加载,我们点击列表项的响应速度变得越来越慢,并且能明显感觉到点击延时的存在,我们通过工具测试一下滑动了多屏之后的性能:

  • 滑动 400 条数据后,对列表项点击事件响应测试。点击响应 8s 延时

小程序动态高度长列表优化实战:解决滑动白屏与性能问题(二)

小程序动态高度长列表优化实战:解决滑动白屏与性能问题(二)

可以从上图看到,在点击之后,FPS 曲线出现了一个很大的波谷,大概8s左右,FPS 最低值到 0。实际的样子就是:我点击了一下列表项,页面就没法操作了,过了一会,页面跳转到了详情页...

方案

taro 框架的虚拟列表,适用于固定高度的长列表。虽然官方文档说支持动态高度,但实际用起来,发现对于高度落差较大的长列表,没法适用,因为不能及时获取到高度。但如果我们能够在列表获取高度时,计算得到列表项高度,再传给 virtual-list,就能直接复用 virtual-list 原有的虚拟列表逻辑,并解决动态高度的问题

可以看下 taro 的 virtual-list 源码

小程序动态高度长列表优化实战:解决滑动白屏与性能问题(二)

我们不难发现,virtual-list 中的列表项的高度其实是由外部传入一个固定高度height来确定,而我们只需要将 Taro 获取高度的逻辑,改成获取外部传入的高度,就可以解决我们的问题。而涉及的代码就就可以从 获取列表项位置获取列表项高度获取列表项偏移量这三处代码入手。我们将 Taro 的 virtual-list 代码复制一份,开始魔改。

我们定义一个 customSize 属性,用于标识是否要用外部传入的列表高度。

关键代码

// Taro/virtual-list/react/createListComponent.js
constructor (props) {
  super(props)
  // ...

  // 新增自定义高度逻辑
  if (props.customSize) {
    this.state.sizeList = this.props.sizeList
  } else {
    this.state.sizeList = new Array(this.props.itemCount).fill(-1)
  }
}

this._getCountSize = (props, count) => {
    // ...      
    // 外部传入自定义的 size
    if (props.customSize) {
      const sizes = props.sizeList.slice(0, count)

      return sizes.reduce((p, a) => {
        return p + this._getSize(a)
      }, 0)
    }
}

this._getSizeUpload = (index, isHorizontal) => {
    // 新增自定义高度逻辑
    if (props.customSize) {
      const { sizeList } = this.props
      return this._getSize(sizeList[index])
    }

    // ...
}

进一步优化

在魔改Taro 的 virtual-list代码的同时,发现一个问题。当我们快速上下滑动列表页面时,即使列表已经触顶或触底了,但是不会触发相应的回调,猜测 Taro 对列表的滑动,做了节流(没有找到相关代码,找到一个issue,但已经关闭了)

问题解决

在列表的最顶端和最低端各放置一根高度为 1px 的透明线条,我们监听着两根线条是否出现在可视区,来判断是触底还是触顶。

小程序动态高度长列表优化实战:解决滑动白屏与性能问题(二)

关键代码

// 解决scrollView置顶后,scrollOffset不为0的问题
const observePage  = () => {
    const observerObjTop = Taro.createIntersectionObserver().relativeToViewport({ top: -position.top });
    observerObjTop.observe(`#todo-list-scroll-line-view-top`, (res) => {
        const isBool = res.intersectionRatio > 0

        if (isBool && resetScroll) {
            resetScroll('top')
        }
    });

    const observerObjBottom = Taro.createIntersectionObserver().relativeToViewport({ bottom: -position.bottom });
    observerObjBottom.observe(`#todo-list-scroll-line-view-bottom`, (res) => {
        const isBool = res.intersectionRatio > 0

        if (isBool && resetScroll) {
            resetScroll('bottom')
        }
    });

    observerObjs.current = [observerObjTop, observerObjBottom]
}

成果

滑动 400 条数据后,对列表项点击事件响应测试

  • 优化前,点击响应 8s
  • 优化后,点击响应 3s

小程序动态高度长列表优化实战:解决滑动白屏与性能问题(二)

小程序动态高度长列表优化实战:解决滑动白屏与性能问题(二)

可以看到之前的波谷已经大大缩小到 3s,FPS 的最低值大于 0,内存也稳定在 73 MB。相比于优化前,性能还是提升了不少,至少不会感觉到明显的点击延迟。

最后

码字不易,各位老铁多支持: 点赞 + 收藏 + 评论

小程序性能检测工具:perfdog.qq.com

代码自取:github.com/lhanyun/lh-…

转载自:https://juejin.cn/post/7270829887530827839
评论
请登录