ForEach: 循环渲染组件
ForEach接口基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在ForEach父容器组件中的子组件
接口描述
ForEach(
arr: Array, // 要遍历的数据数组
itemGenerator: (item: any, index?: number) => void, // 页面组件生成函数
keyGenerator?: (item: any, index?: number): string => string // 键生成函数,为数组每一项生成一个唯一标识,组件是否重新渲染的判断标准
)
使用建议
- 尽量避免在最终的键值生成规则中包含数据项索引index,以防止出现渲染结果非预期和渲染性能降低。如果业务确实需要使用index,例如列表需要通过index进行条件渲染,开发者需要接受ForEach在改变数据源后重新创建组件所带来的性能损耗。
- 为满足键值的唯一性,对于对象数据类型,建议使用对象数据中的唯一id作为键值。
- 基本数据类型的数据项没有唯一ID属性。如果使用基本数据类型本身作为键值,必须确保数组项无重复。因此,对于数据源会发生变化的场景,建议将基本数据类型数组转化为具备唯一ID属性的对象数据类型数组,再使用ID属性作为键值生成规则。
不推荐案例
开发者在使用ForEach的过程中,若对于键值生成规则的理解不够充分,可能会出现错误的使用方式。错误使用一方面会导致功能层面问题,例如渲染结果非预期,另一方面会导致性能层面问题,例如渲染性能降低。
ForEach使用小案例
// 定义结构体
class Item {
name: string
image: ResourceStr
price: number
discount: number
constructor(name: string, image: ResourceStr, price: number, discount: number = 0) {
this.name = name
this.image = image
this.price = price
this.discount = discount
}
}
@Entry
@Component
struct Index {
// 商品数据
private items: Array<Item> = [
new Item("Mate60", $r("app.media.mate60"), 5999, 500),
new Item("mate60pro", $r("app.media.mate60pro"), 6999),
new Item("mate60pro+", $r("app.media.mate60proplus"), 8999),
new Item("mate60rs", $r("app.media.mate60rs"), 12999),
new Item("matebook", $r("app.media.matebook"), 5999),
]
build() {
Column({ space: 8 }) {
// 定义标题栏
Row() {
Text("商品列表")
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.margin({ bottom: 20 })
// 使用ForEach遍历商品数据
ForEach(
this.items,
(item: Item) => {
// ForEach函数内部创建一个Row容器
Row({ space: 10 }) {
// 插入图片
Image(item.image)
.width(100)
// 因为商品信息是垂直排列,所以需要一个Column容器
Column({ space: 4 }) {
// 根据是有折扣判断显示方式
if (item.discount) {
Text(item.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('原价:¥' + item.price)
.fontSize(14)
.fontColor('#CCC')
// 添加中划线
.decoration({type:TextDecorationType.LineThrough})
Text('折扣价:¥' + (item.price - item.discount))
.fontSize(18)
.fontColor('#F36')
Text('补贴价:¥' + item.discount)
.fontSize(18)
.fontColor('#F36')
} else {
Text(item.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('¥' + item.price)
.fontSize(18)
.fontColor('#F36')
}
}
.height('100%')
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.backgroundColor('#218c8a8a')
.borderRadius(20)
.height(100)
}
)
}
}
}