ForEach循环及@Observed的使用
仅讲解常见的业务开发需求使用到的地方,不详细处可查看官方文档。
1、原始类型的数组
- ForEach循环中的
item
项不能直接修改,需要改数据只能修改@State
修饰的数组。
@Entry
@Component
struct Index {
@State list:string[] = ['小明','小花','大黄']
build() {
Column(){
ForEach(this.list,(item:string,index:number)=>{
Row(){
Text(item)
.fontSize(30)
Button('修改').onClick(()=>{
//这样子修改是不对的
// item = `${item}--修改了`
//而应该这样修改
this.list[index] = `${item}--修改了`
})
.margin({left:10})
}
.margin({bottom:15})
},(index:number):string=>index.toString())
}
.height('100%')
.width('100%')
}
}
2、对象类型数组
- 对象数组使用
ForEach
循环时,父组件对象数组使用@State
修饰,数组中的对象必须是使用new
操作符创建,字面量定义的数据修改后页面不能更新 - 需使用
@Observed
装饰器修饰对象的类 - 循环的内容需提出成单独组件,使用
@Copmonent
修饰,里面使用@ObjectLink
修饰接收的数据对象 @ObjectLink
修饰的数据对象不能直接修改,如要修改数据可将父组件中的对象数组传递到子组件,子组件使用@Link
修饰接收数据。- 在一个文件中如果类(如
StudentInfo
)定义了构造函数constructor
,以此类为类型的字面量数组会报错(如list
数组),可以定义interface
,让类实现此接口。 - 子组件中
@ObjectLink
修饰的对象必须是@Observed
修饰的类的类型。
注意:
@Observed
配合@ObjectLink
解决的只是对象数组数据修改后页面能监听到并自动更新的问题。- 至于在子组件修改父组件数据,可以通过父组件传给子组件使用@Link双向绑定,也可以通过
emitter
在父组件aboutToAppear
中注册监听事件,然后在子组件触发(注意需要在aboutToDisAppear
中销毁)。
补充
其实对于对象数组,虽然@State
只能监听到数组的第一层,我们也可以使用splice
通过重置引用的方式来使页面更新,但对于频繁的更新且有图片的数据,会造成图像闪烁的问题(也很好理解,就是频繁的删除和重新插入对象),对一般低频场景使用也完全足够。
interface IStudentInfo {
name: string
age: number
gradle: string
yuwen: number
shuxue: number
sure: boolean
}
@Observed
class StudentInfo implements IStudentInfo {
name: string = ''
age: number = 0
gradle: string = '一年级'
yuwen: number = 0
shuxue: number = 0
sure: boolean = false
constructor(instance: IStudentInfo) {
this.name = instance.name
this.age = instance.age
this.gradle = instance.gradle
this.yuwen = instance.yuwen
this.shuxue = instance.shuxue
this.sure = instance.sure
}
}
const list: IStudentInfo[] = [
{
name: '小明',
age: 12,
gradle: '三年级',
yuwen: 80,
shuxue: 76,
sure: false
},
{
name: '小花',
age: 12,
gradle: '三年级',
yuwen: 80,
shuxue: 76,
sure: false
},
{
name: '大黄',
age: 18,
gradle: '三年级',
yuwen: 80,
shuxue: 76,
sure: false
},
]
@Entry
@Component
struct Index {
@State studentlist: IStudentInfo[] = []
aboutToAppear(): void {
// 初始化数据
list.forEach((value: IStudentInfo) => {
this.studentlist.push(new StudentInfo(value))
})
//也可以使用.emitter.on()来注册监听事件来修改studentlist数据
}
aboutToDisappear(): void {
//emitter.off()
}
build() {
Column() {
ForEach(this.studentlist, (item: StudentInfo, index: number) => {
StudentCardItem({ item: item, index: index, list: this.studentlist })
}, (index: number): string => index.toString())
}
.height('100%')
.width('100%')
.backgroundColor('#efefef')
}
}
@Component
struct StudentCardItem {
@ObjectLink item: StudentInfo
@Link list: IStudentInfo[]
@Prop index: number = 0
build() {
Column() {
Text(this.item.name)
.fontSize(24)
Row() {
Text(`语文:${this.item.yuwen}`)
.fontSize(20)
Text(`数学:${this.item.shuxue}`)
.fontSize(20)
Text(`确认成绩:${this.item.sure ? '是' : '否'}`)
.fontSize(20)
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
Button(`${this.item.sure ? '取消' : '确认'}`)
.onClick(() => {
//这样子修改是不对的
// item.sure = !item.sure
//这样子修改
this.list[this.index].sure = !this.list[this.index].sure
//也可以使用emitter.emit来触发事件修改父组件数据
})
.width(60)
.height(30)
.fontSize(14)
.margin({ top: 10 })
}
.width('100%')
.alignItems(HorizontalAlign.Start)
.padding({
left: 15,
right: 15,
top: 15,
bottom: 15
})
.backgroundColor('#fff')
.margin({ bottom: 20 })
}
}
如果对你有帮助,点个赞呗!!!