HarmonyOS鸿蒙Next中List包裹Repeat开启虚拟滚动数据量大的时候调用scrollTo回到顶部会卡顿

HarmonyOS鸿蒙Next中List包裹Repeat开启虚拟滚动数据量大的时候调用scrollTo回到顶部会卡顿

scrollTo({
    xOffset: 0, yOffset: 0
})

List 包裹Repeat 开启虚拟滚动

数据有八百多条 手动滑倒最底部

这个时候调用scrollTo 回到顶部会卡顿2 秒钟 才会回到顶部

4 回复

开发者你好,可以参考以下方案优化性能:

【解决方案】 可以采用先调用scrollToIndex关闭动画跳转到目标附近位置,再调用scrollToIndex开启动画滚动到目标位置的间接跳转的方式,优化性能。 以纵向滚动的5000个元素的长列表,调用scroller反复滚动到列表顶部和底部为例,示例代码如下:

@Entry
@ComponentV2
export struct virtrulScroll {
  private itemHeight: number = 50;
  private readonly list: string[] = Array
    .from({ length: 5000 }, (_: number, i: number) => i + 1)
    .map((i: number) => `index: ${i}`);
  private readonly scroller: Scroller = new Scroller();

  build() {
    Column() {
      Row({ space: 10 }) {
        Button('scroll to top')
          .fontSize(13)
          .onClick(() => {
            // 用currentOffset().yOffset获取当前滑动偏移量除以单项高度获得index做判断,离目标位置超过200项则以关闭动效先滚动到目标位置附近
            if (this.scroller.currentOffset().yOffset / this.itemHeight >= 200) {
              this.scroller.scrollToIndex(200, false);
            }
            this.scroller.scrollToIndex(0, true);
          });
        Button('scroll to bottom')
          .fontSize(13)
          .onClick(() => {
            if (this.scroller.currentOffset().yOffset / this.itemHeight <= this.list.length - 200) {
              this.scroller.scrollToIndex(this.list.length - 200, false);
            }
            this.scroller.scrollToIndex(this.list.length - 1, true);
          });
        Button('jump 1000')
          .fontSize(13)
          .onClick(() => {
            console.info('currentoffset: ', this.scroller.currentOffset().yOffset);
            this.scroller.scrollToIndex(1000, false);
          });
      };

      List({
        scroller: this.scroller,
      }) {
        Repeat(this.list)
          .key((item: string) => item)
          .virtualScroll({ totalCount: this.list.length })
          .templateId(() => '1')
          .template('1', (repeatItem: RepeatItem<string>) => {
            ListItem() {
              Text(repeatItem.item)
                .width('100%')
                .height(this.itemHeight)
                .padding(5)
                .textAlign(TextAlign.Center);
            };
          })
          .each((repeatItem: RepeatItem<string>) => {
            ListItem() {
              Text(repeatItem.item)
                .width('100%')
                .height(this.itemHeight)
                .padding(5);
            };
          });
      }
      .width('100%')
      .height(200)
      .layoutWeight(1);
    }.backgroundColor(Color.White);
  }
}

或者可以考虑使用Repeat的virtualScroll模式。Repeat根据容器组件的有效加载范围(可视区域+预加载区域)加载子组件。当容器滑动/数组改变时,Repeat会根据父容器组件传递的参数重新计算有效加载范围,实时管理列表节点的创建与销毁。该模式适合需要懒加载的长数据列表/通过组件复用优化性能表现的场景。

更多关于HarmonyOS鸿蒙Next中List包裹Repeat开启虚拟滚动数据量大的时候调用scrollTo回到顶部会卡顿的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


**问题描述:**在list中使用scrollTo方法会卡两秒

详细分析:

scrollTo({yOffset:0,xOffset:0})

根据api分析,滚动时需要计算x和y的偏移量,有一个计算的过程,如果数据量过大,就会导致计算时间的增加,这是他卡顿的原因

**解决方案:**如果你是为了实现回到顶部的功能,可以通过一下两个api实现:

方法一:

this.scroller.scrollToIndex(0)

方法二:

this.scroller.scrollEdge(Edge.Top)

因为这两个api不涉及计算,所以速度很快,经过验证,没有任何卡顿

如果对你有帮助,望采纳!

在HarmonyOS Next中,List组件包裹Repeat组件并开启虚拟化后,数据量过大时scrollTo操作卡顿是由于虚拟滚动机制下渲染节点回收与复用导致。当执行快速定位时,系统需重新计算布局并渲染可视区域外内容,引发性能瓶颈。可通过以下方案优化:1. 使用LazyForEach替代Repeat实现动态加载;2. 设置cachedCount属性预缓存可视区外节点;3. 分批加载数据避免单次渲染过量条目。需确保scrollTo调用时机在列表渲染稳定后。

在HarmonyOS Next中,当List组件包裹Repeat并开启虚拟滚动时,处理大量数据(如800条)后调用scrollTo回到顶部出现卡顿,主要原因是虚拟滚动机制下DOM节点复用与滚动位置计算的性能瓶颈。建议优化以下方面:

  1. 分批加载数据:通过onReachEnd事件动态加载数据,避免一次性渲染全部条目,减少初始渲染压力。

  2. 优化scrollTo调用

    • 添加动画参数,如duration: 0,强制无过渡效果:scrollTo({ xOffset: 0, yOffset: 0, duration: 0 })
    • 在调用前检查滚动状态,避免重复触发。
  3. 减少条目渲染复杂度:简化Repeat内组件的布局和样式,避免深层次嵌套或重绘操作。

  4. 使用键值优化:为Repeat项设置唯一key,帮助系统高效复用节点,例如通过数据ID绑定。

  5. 监控滚动事件:必要时通过ScrollController预计算位置,减少实时计算开销。

通过结合数据分片和滚动参数调整,可显著提升响应速度,消除卡顿现象。

回到顶部