HarmonyOS鸿蒙Next中LazyForEach滑动到数据第一条的时候数据list没错,但是页面显示列如下标1的数据显示在了下标0

HarmonyOS鸿蒙Next中LazyForEach滑动到数据第一条的时候数据list没错,但是页面显示列如下标1的数据显示在了下标0

重现步骤为:  向下滑动加载后面的数据时
  在滑动回到第一条 显示的数据错乱了
private datasource : CommonDataSource<CheckRecord> = new CommonDataSource()
Grid(){
  LazyForEach(this.datasource,(item:CheckRecord,index:number) => {
    GridItem() {
      MyCard({item})
    }.height(190).width("100%").borderRadius(10).backgroundColor("white")
  },(item:CheckRecord) => item.exeConditionId)

}
@Reusable
@Component
struct MyCard {
  @Prop item:CheckRecord
  @Builder
  iconHead(){
    Text().height(12).width(4).backgroundColor("#0A59F7").margin({left:15,right:8})
  }

  @Builder
  labelText(name: string,value?:string,suffix:string = ''){
    Row() {
      Text(name).fontSize(14).fontColor("#666666").padding({left:15})
      Text(value ? value + suffix : '').layoutWeight(1).maxLines(1).textOverflow({overflow: TextOverflow.Ellipsis})
    }.width("50%").height("20%")
  }

  build() {
    Column(){
      Row() {
        this.iconHead()
        Text(this.item.resBarnRoomName).fontSize(16).fontWeight(FontWeight.Bold).width('78%')
        Text("查看").width('22%')
          .padding({right:"10%"}).fontColor("#0088FE")
          .fontSize(16)
          .onClick((e:ClickEvent) => {
            ZRouter.getInstance().setParam({
              exeConditionId: this.item.exeConditionId,
              resBarnRoomId: this.item.resBarnRoomId
            }).navigation('fun/GranaryVisualizeGraph')
          })
      }.height("20%").width('100%').borderColor("#ebebeb").borderWidth({bottom:1})
      Flex({wrap:FlexWrap.Wrap}){
        Row(){
          Text(`采集时间:`).fontSize(14).fontColor("#666666")
          Text(`${this.item.dateCheck}`)
        }.width("100%").height("18%").padding({left:15})
        this.labelText("品名:", this.item.resPdtName)
        this.labelText("最高温:",this.item.max?.toFixed(1),'℃')
        this.labelText("最低温:", this.item.min?.toFixed(1),'℃')
        this.labelText("平均温:",this.item.avg?.toFixed(1),'℃')
        this.labelText("仓温:",this.item.temp?.toFixed(1),'℃')
        this.labelText("仓湿:",this.item.hum?.toFixed(1),'%')
      }
    }.width("100%").height("100%")
  }
}

更多关于HarmonyOS鸿蒙Next中LazyForEach滑动到数据第一条的时候数据list没错,但是页面显示列如下标1的数据显示在了下标0的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复
class MyDataSource implements IDataSource {
  private dataArray: string[] = []
  private listener: DataChangeListener | undefined

  public totalCount(): number {
    return this.dataArray.length
  }

  public getData(index: number): string {
    return this.dataArray[index]
  }

  public pushData(data: string): void {
    this.dataArray.push(data)
  }

  public reloadListener(): void {
    this.listener?.onDataReloaded()
  }

  public registerDataChangeListener(listener: DataChangeListener): void {
    this.listener = listener
  }

  public unregisterDataChangeListener(listener: DataChangeListener): void {
    this.listener = undefined
  }
}

@Entry
@Component
struct ReusableLazyForEachCase {
  private data: MyDataSource = new MyDataSource()

  aboutToAppear() {
    for (let i = 1; i < 100; i++) {
      this.data.pushData(i + "")
    }
  }

  build() {
    Column() {
      List() {
        LazyForEach(this.data, (item: string) => {
          ListItem() {
            MyCard({ item })
          }.height(190).width("100%").borderRadius(10).backgroundColor("white")
        }, (item: string) => item)
      }
      .width('100%')
      .height('100%')
      .edgeEffect(EdgeEffect.Spring)
      .scrollBar(BarState.On)
    }
    .width('100%')
    .height('100%')
  }
}

@Reusable
@Component
struct MyCard {
  @Prop item: string = ''

  @Builder
  iconHead() {
    Text().height(12).width(4).backgroundColor("#0A59F7").margin({ left: 15, right: 8 })
  }

  @Builder
  labelText() {
    Row() {
      Text(this.item).fontSize(14).fontColor("#666666").padding({ left: 15 })
      Text(this.item).layoutWeight(1).maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })
    }.width("50%").height("20%")
  }

  build() {
    Column() {
      Row() {
        this.iconHead()
        // Text(this.item.resBarnRoomName).fontSize(16).fontWeight(FontWeight.Bold).width('78%')
        Text("查看").width('22%')
          .padding({ right: "10%" }).fontColor("#0088FE")
          .fontSize(16)
        // .onClick((e:ClickEvent) => {
        //   // ZRouter.getInstance().setParam({
        //   //   exeConditionId: this.item.exeConditionId,
        //   //   resBarnRoomId: this.item.resBarnRoomId
        //   }).navigation('fun/GranaryVisualizeGraph')
        // })
      }.height("20%").width('100%').borderColor("#ebebeb").borderWidth({ bottom: 1 })

      Flex({ wrap: FlexWrap.Wrap }) {
        Row() {
          Text(`采集时间:`).fontSize(14).fontColor("#666666")
          Text(`${this.item}`)
        }.width("100%").height("18%").padding({ left: 15 })

        this.labelText()
        this.labelText()
        this.labelText()
        this.labelText()
        this.labelText()
        this.labelText()
      }
    }.width("100%").height("100%")
  }
}

用简易的数据,好像没有出现楼主的问题,建议查看打印一下id是否存在重复(keyGenerator 生成的键)标识组件

这个组件的简解我也写过:https://developer.huawei.com/consumer/cn/blog//topic/03197384103127220

更多关于HarmonyOS鸿蒙Next中LazyForEach滑动到数据第一条的时候数据list没错,但是页面显示列如下标1的数据显示在了下标0的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


可能为以下问题

  1. 键值生成器问题

LazyForEach的第三个参数要求生成 唯一且稳定 的键值。若item.exeConditionId存在重复或动态变化,会导致组件复用混乱。

强化键值唯一性

// 修改键生成逻辑,确保唯一性
LazyForEach(this.datasource, (item: CheckRecord, index: number) => {
  // 使用稳定唯一键组合
  GridItem() { /* ... */ }
}, (item: CheckRecord) => `${item.exeConditionId}_${index}`) // 添加索引提升唯一性
  1. 可复用组件数据同步问题

@Reusable装饰器可能导致组件复用后未及时更新@Prop属性,造成旧数据残留。

调整组件复用策略

// 去除[@Reusable](/user/Reusable)装饰器避免复用残留
@Component
struct MyCard {
  [@Prop](/user/Prop) item: CheckRecord
  // 原有构建逻辑...
}
  1. 数据更新机制不完整

数据源更新后未正确触发onDataReloaded或onDatasetChange方法,导致界面未及时刷新。

你检查一下 item.exeConditionId 是不是重复了。

  • 键值生成器必须针对每个数据生成唯一的值,如果键值相同,将导致键值相同的UI组件渲染出现问题。

键值生成规则

在LazyForEach循环渲染过程中,系统为每个item生成一个唯一且持久的键值,用于标识对应的组件。键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并基于新的键值创建新的组件。

LazyForEach提供了参数keyGenerator,开发者可以使用该函数生成自定义键值。如果未定义keyGenerator函数,ArkUI框架将使用默认的键值生成函数:(item: Object, index: number) => { return viewId + ‘-’ + index.toString(); }。viewId在编译器转换过程中生成,同一个LazyForEach组件内的viewId一致。

键值应满足以下条件。

  1. 键值具有唯一性,每个数据项对应的键值互不相同。
  2. 键值具有一致性,数据项不变时对应的键值也不变。

上述条件保证LazyForEach正确、高效地更新子组件,否则可能存在渲染结果异常、渲染效率降低等问题。

在HarmonyOS鸿蒙Next中,LazyForEach组件在滑动到第一条数据时出现显示错位,通常是由于组件复用机制导致的渲染状态未及时更新。可检查数据源与组件键值绑定是否唯一稳定,确保数据变更时触发正确的界面刷新。建议在数据项更新时调用刷新方法,并验证LazyForEach的组件生成逻辑与数据索引严格对应。

这个问题通常是由于LazyForEach在复用组件时,数据绑定没有正确更新导致的。从代码来看,你的MyCard组件使用了@Reusable装饰器,这会导致组件复用,但@Prop装饰的属性在复用时可能不会及时更新。

建议检查以下几点:

  1. 确保exeConditionId作为key是唯一且稳定的。如果数据源变化时key不唯一,会导致组件复用混乱。

  2. 尝试将@Prop改为@Link@ObjectLink,确保数据变化时能正确触发UI更新:

@Link item: CheckRecord
  1. 如果问题仍然存在,可以暂时移除@Reusable装饰器测试是否解决。

  2. 确认CommonDataSource的数据更新机制,确保数据变化时能正确通知到LazyForEach。

这种数据错乱问题在列表快速滚动时比较常见,主要原因是组件复用机制与数据更新不同步导致的。

回到顶部