赞
踩
ForEach 接口,基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在 ForEach 父容器组件中的子组件。例如,ListItem 组件要求 ForEach 的父容器组件必须为 List 组件。
ForEach(
arr: Array,
itemGenerator: (item: Array, index?: number) => void,
keyGenerator?: (item: Array, index?: number): string => string
)
参数名 | 参数类型 | 必填 | 参数描述 |
---|---|---|---|
arr | Array | Yes | 数据源,为 Array 类型的数组 说明: ⇒ 可以设置为空数组,此时不会创建子组件 ⇒ 可以设置返回值为数组类型的函数,例如arr.slice(1, 3) 但设置的函数不应改变包括数组本身在内的任何状态变量, 例如不应使用 Array.splice(),Array.sort() 或Array.reverse() 这些会改变原数组的函数。 |
itemGenerator | (item: any, index?: number) => void | Yes | 组件生成函数 ⇒ 为数组中的每个元素创建对应的组件 参数: ⇒ item:arr 数组中的数据项 ⇒ index:arr 数组中的数据项索引(可选) 说明: ⇒ 组件的类型必须是 ForEach 的父容器所允许的。 例如,ListItem 组件要求 ForEach 的父容器组件必须为 List 组件。 |
keyGenerator | (item: any, index?: number) => string | No | 键值生成函数 ⇒ 为数据源 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') } }
运行效果:
在 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 非首次渲染。
在 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) }
运行效果:
在上述代码中,键值生成规则是 keyGenerator 函数的返回值 item。在 ForEach 渲染循环时,为数据源数组项依次生成键值 First
、Second
和 Third
,并创建对应的 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) } }
运行效果:
在该示例中,最终键值生成规则为 item。当 ForEach 遍历数据源 simpleList,遍历到索引为 1 的 Second 时,按照最终键值生成规则生成键值为 Second 的组件并进行标记。当遍历到索引为 2 的 Second 时,按照最终键值生成规则当前项的键值也为 Second,此时不再创建新的组件。
在 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) } }
运行效果:
从本例可以看出 @State 能够监听到简单数据类型数组数据源 simpleList 数组项的变化。
First
、Second
和 new Third
。First
和 Second
在上次渲染中已经存在,所以 ForEach 复用了对应的组件并进行了渲染。对于第三个数组项 “new Third”,由于其通过键值生成规则 item 生成的键值 new Third
在上次渲染中不存在,因此 ForEach 为该数组项创建了一个新的组件。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。