当前位置:   article > 正文

写给初学者的 HarmonyOS 教程 -- 循环渲染(ForEach)_harmonyos foreach

harmonyos foreach

ForEach 接口,基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在 ForEach 父容器组件中的子组件。例如,ListItem 组件要求 ForEach 的父容器组件必须为 List 组件。

一、接口描述

ForEach(
  arr: Array,
  itemGenerator: (item: Array, index?: number) => void,
  keyGenerator?: (item: Array, index?: number): string => string
)
  • 1
  • 2
  • 3
  • 4
  • 5
参数名参数类型必填参数描述
arrArrayYes数据源,为 Array 类型的数组

说明:
⇒ 可以设置为空数组,此时不会创建子组件
⇒ 可以设置返回值为数组类型的函数,例如arr.slice(1, 3)

但设置的函数不应改变包括数组本身在内的任何状态变量,
例如不应使用 Array.splice(),Array.sort() 或Array.reverse()
这些会改变原数组的函数。
itemGenerator(item: any, index?: number) => voidYes组件生成函数

⇒ 为数组中的每个元素创建对应的组件

参数:
⇒ item:arr 数组中的数据项
⇒ index:arr 数组中的数据项索引(可选)

说明:
⇒ 组件的类型必须是 ForEach 的父容器所允许的。
例如,ListItem 组件要求 ForEach 的父容器组件必须为 List 组件。
keyGenerator(item: any, index?: number) => stringNo键值生成函数

⇒ 为数据源 arr 的每个数组项生成唯一且持久的键值,
函数返回值为开发者自定义的键值生成规则。

参数:
⇒ item:arr 数组中的数据项
⇒ index:arr 数组中的数据项索引(可选)

说明:
⇒ 如果函数缺省,框架默认的键值生成函数为
(item: T, index: number) => { return index + ‘__’ + JSON.stringify(item); }
⇒ 键值生成函数不应改变任何组件状态。
@Component
struct ForEachTest {

  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  
  build() {
    List({ space: 20, initialIndex: 0 }) {
      ForEach(this.arr, (item) => {
        ListItem() {
          Text('' + item)
            .width('100%').height(100).fontSize(16)
            .textAlign(TextAlign.Center).borderRadius(10).backgroundColor(0xFFFFFF)
        }
      }, item => item)
    }
    .scrollBar(BarState.Auto)
    .backgroundColor('#FFF1F3F5')
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行效果:

在这里插入图片描述

二、键值生成规则

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

ForEach 提供了一个名为 keyGenerator 的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义 keyGenerator 函数,则 ArkUI 框架会使用默认的键值生成函数,即:

(item: any, index: number) => { return index + ‘__’ + JSON.stringify(item); }

ArkUI 框架对于 ForEach 的键值生成有一套特定的判断规则,这主要与 itemGenerator 函数的第二个参数 index 以及keyGenerator 函数的返回值有关。总的来说,只有当开发者在 itemGenerator 函数中声明了 index 参数,并且自定义的keyGenerator 函数返回值中不包含 index 参数时,ArkUI 框架才会在开发者自定义的 keyGenerator 函数返回值前添加 index 参数,作为最终的键值。在其他情况下,系统将直接使用开发者自定义的 keyGenerator 函数返回值作为最终的键值。如果 keyGenerator 函数未定义,系统将使用上述默认的键值生成函数。具体的键值生成规则判断逻辑如下图所示。

在这里插入图片描述

三、组件创建规则

在确定键值生成规则后,ForEach 的第二个参数 itemGenerator 函数会根据键值生成规则为数据源的每个数组项创建组件。

组件的创建包括两种情况:ForEach 首次渲染ForEach 非首次渲染

3.1 首次渲染

在 ForEach 首次渲染时,会根据前述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件。

@Entry
@Component
struct ListTest {
  @State simpleList: Array<string> = ['First', 'Second', 'Third'];

  build() {
    Row() {
      Column() {
        ForEach(this.simpleList, (item: string) => {
          ChildItem({ item: item })
        }, (item: string) => item)
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
    .backgroundColor(0xF1F3F5)
  }
}

@Component
struct ChildItem {
  @Prop item: string;

  build() {
    Text(this.item)
      .fontSize(50)
  }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

运行效果:
在这里插入图片描述

在上述代码中,键值生成规则是 keyGenerator 函数的返回值 item。在 ForEach 渲染循环时,为数据源数组项依次生成键值 FirstSecondThird,并创建对应的 ChildItem 组件渲染到界面上。

当不同数组项按照键值生成规则生成的键值相同时,框架的行为是未定义的。例如,在以下代码中,ForEach 渲染相同的数据项 Second 时,只创建了一个 ChildItem 组件,而没有创建多个具有相同键值的组件。

@Entry
@Component
struct ListTest {
  @State simpleList: Array<string> = ['First', 'Second', 'Second', 'Third'];

  build() {
    Row() {
      Column() {
        ForEach(this.simpleList, (item: string) => {
          ChildItem({ item: item })
        }, (item: string) => item)
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
    .backgroundColor(0xF1F3F5)
  }
}

@Component
struct ChildItem {
  @Prop item: string;

  build() {
    Text(this.item)
      .fontSize(50)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

运行效果:

在这里插入图片描述

在该示例中,最终键值生成规则为 item。当 ForEach 遍历数据源 simpleList,遍历到索引为 1 的 Second 时,按照最终键值生成规则生成键值为 Second 的组件并进行标记。当遍历到索引为 2 的 Second 时,按照最终键值生成规则当前项的键值也为 Second,此时不再创建新的组件。

3.2 非首次渲染

在 ForEach 组件进行非首次渲染时,它会检查新生成的键值是否在上次渲染中已经存在。如果键值不存在,则会创建一个新的组件;如果键值存在,则不会创建新的组件,而是直接渲染该键值所对应的组件。例如,在以下的代码示例中,通过点击事件修改了数组的第三项值为"new three",这将触发 ForEach 组件进行非首次渲染。

@Entry
@Component
struct ListTest {
  @State simpleList: Array<string> = ['First', 'Second', 'Third'];

  build() {
    Row() {
      Column() {
        Text('点击修改第 3 个数组项的值')
          .fontSize(24)
          .fontColor(Color.Red)
          .onClick(() => {
            this.simpleList[2] = 'new Third';
          })

        ForEach(this.simpleList, (item: string) => {
          ChildItem({ item: item })
            .margin({ top: 20 })
        }, (item: string) => item)
      }
      .width('100%')
      .height('100%')
    }
    .height('100%')
    .backgroundColor(0xF1F3F5)
  }
}

@Component
struct ChildItem {
  @Prop item: string;

  build() {
    Text(this.item)
      .fontSize(50)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

运行效果:

在这里插入图片描述

从本例可以看出 @State 能够监听到简单数据类型数组数据源 simpleList 数组项的变化。

  1. 当 simpleList 数组项发生变化时,会触发 ForEach 进行重新渲染。
  2. ForEach 遍历新的数据源 [‘First’, ‘Second’, ‘new Third’],并生成对应的键值 FirstSecondnew Third
  3. 其中,键值 FirstSecond 在上次渲染中已经存在,所以 ForEach 复用了对应的组件并进行了渲染。对于第三个数组项 “new Third”,由于其通过键值生成规则 item 生成的键值 new Third 在上次渲染中不存在,因此 ForEach 为该数组项创建了一个新的组件。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/279047?site
推荐阅读
相关标签
  

闽ICP备14008679号