一.官方文档
ForEach的官方文档!
二.基本语法
ForEach(arr: Array, //要遍历的数组
itemGenerator: (item: any, index: number) => {
//页面组件生成函数
},
keyGenerator?: (item: any, index: number) =>{
//键生产函数,为数组每一项生成唯一标识,是组件是否重新渲染的判断标准
}
)
arr:数组
itemGenerator:组件生成的回调函数,循环渲染组件
(item: any, index: number) =>{ 需要循环渲染的组件 } -- item:数组遍历出来的元素,index:元素下标
itemGenerator:键值生成的回调函数。用于给循环生成的组件绑定一个唯一且固定的键值
(item: any, index: number) =>{ 写循环生成键值逻辑 } -- item:数组遍历出来的元素,index:元素下标
ForEach接口基于数组类型数据来进行对组件的循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在ForEach父容器组件中的子组件。
来看看文档吧:
参数名 |
参数类型 |
必填 |
参数描述 |
---|---|---|---|
arr |
Array<any> |
是 |
数据源,为Array类型的数组。 说明: - 可以设置为空数组,此时不会创建子组件。 - 可以设置返回值为数组类型的函数,例如arr.slice(1, 3),但设置的函数不应改变包括数组本身在内的任何状态变量,例如不应使用Array.splice(),Array.sort()或Array.reverse()这些会改变原数组的函数。 |
itemGenerator |
(item: any, index: number) => void |
是 |
组件生成函数。 - 为数组中的每个元素创建对应的组件。 - item参数:arr数组中的数据项。 - index参数(可选):arr数组中的数据项索引。 说明: - 组件的类型必须是ForEach的父容器所允许的。例如,ListItem组件要求ForEach的父容器组件必须为List组件。 |
keyGenerator |
(item: any, index: number) => string |
否 |
键值生成函数。 - 为数据源arr的每个数组项生成唯一且持久的键值。函数返回值为开发者自定义的键值生成规则。 - item参数:arr数组中的数据项。- index参数(可选):arr数组中的数据项索引。 说明: - 如果函数缺省,框架默认的键值生成函数为(item: T, index: number) => { return index + '__' + JSON.stringify(item); } - 键值生成函数不应改变任何组件状态。 |
文档内容比较多,我们来简单总结一下:
先创建一个数组就比如叫titles,然后用foreach(this.来引用titles,(item:类型,index:number)=>{})
item和index即参数变量名,可以换成别的,a啊,b呀无所谓item代表遍历时数组中的元素,index代表数组下标
类型要与数组元素类型一致,类型可省,但建议写上方便后期引用。
keyGenerator 通常可省略,系统会有个默认生成值为:index + '_' + JSON.stringify(item)
自己写的话要注意确保每个数组元素生成的结果要不一样,有然相同项只会生成一个UI组件;而且要确保新加入的项不会和原有项生成相同结果,不然UI刷新会受影响,因为只有key变化时UI才刷新。
来渲染个小数组练练手吧:
原格式里item是参数变量,可取任何合规名字,类型是 any,即 arr 可以是任意类型的数组。这里的a只是给item换个名而已,所以这里a代表遍历时数组 III 中三个数组元素,因为是循环渲染,ForEach生成三次。
接下来实现实例吧:
三.实现ForEach循环渲染
最终页面:
1.分析页面
还记得要构建一个页面的第一步吗?
分析
1.1商品从上至下排列——》确定布局Column
1.2标题文字,选择嵌套一个Row布局
1.3商品布局
可以发现商品的布局都是相同的,左侧图片右侧两行文字。那我们就可以实现一个然后使用循环渲染来实现。
图片与文字是在一行中——》嵌套Row容器
右侧文字竖直排列——》嵌套Column容器
2.实现一个商品
2.1嵌套Row容器设置图片
.padding(10) 设置容器内部边距
2.2再次嵌套Column容器
添加属性,使其置于交叉轴开始端。
一个商品的效果就实现了,接下来只要使用ForEach循环渲染来实现即可。
3.ForEach实现
首先创建一个类和数组来存放商品信息。
使用this.来引用Item数组,再为组件生成函数添加类型。
最后再将显示的固定量改变为变量,即从数组中获取。
这样就达到了预期效果:
Watch Fit 3 现补贴50元,更新商品列表:
分析变更:页面无较大变化,Fit 3右侧Column容器中两个文本变为四个。但依旧使用ForEach循环渲染,需要对是否有补贴进行判断。若补贴不为0,则使用新布局。
在Item类在新增变量discount作为补贴价,且初值设置为0,若后期未设discount则默认为0。
在循环渲染中使用if...else语句进行判断选择相应布局。
更新后:
最终代码:
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:Item[]=[ //Item类型 (Array<Item>)
new Item('WATCH FIT 3',$r('app.media.watchfit3'),999,50),
new Item('Pura 70',$r('app.media.pura70'),6999),
new Item('Mate X5',$r('app.media.mateX5'),11999),
new Item('Matepad 11.5S',$r('app.media.matePad'),2299),
new Item('MateBook XPro',$r('app.media.mateBookXPro'),19999),
new Item('FreeBuds Lipstick 2',$r('app.media.freeBudslipstick2'),1999)
]
build() {
Column({space:4}) {
Row(){
Text('商品列表')
.fontSize(30)
.fontStyle(FontStyle.Italic)
.fontWeight(FontWeight.Bold)
}
.width('100%')
ForEach(
this.items,
(item:Item)=>{ //:Item(类型)可不写,若不写下方无法直接弹出其can'shu
Row({space:10}){
Image(item.image)
.width(100)
Column({space:4}){
if(item.discount) {
Text(item.name)
.fontWeight(FontWeight.Bold)
.fontSize(20)
Text('¥'+item.price)
.fontSize(15)
.fontColor('#CCC')
.decoration({type: TextDecorationType.LineThrough})
//文本装饰线样式及其颜色
Text('补贴:¥'+item.discount)
.fontSize(16)
.fontColor(Color.Red)
Text('折扣价:¥'+(item.price-item.discount))
.fontSize(17)
.fontColor(Color.Red)
} else {
Text(item.name)
.fontWeight(FontWeight.Bold)
.fontSize(20)
Text('¥'+item.price)
.fontSize(17)
.fontColor(Color.Red)
}
}
.height('100%')
.alignItems(HorizontalAlign.Start) //交叉轴上对齐方式
}
.height(120) //每一行的行高固定
.width('100%')
.backgroundColor(Color.White)
.borderRadius(20) //边框圆角
.padding(10)
}
)
}
.height('100%')
.width('100%')
.backgroundColor('#FFECECEC')
.padding(20) //组件内部间距
}
}
静水深流,生活亦需内敛之美!