- 如果父组件同时去修改子组件所对应的 @State 状态变量时,那么子组件的这俩个 @Prop 状态变量的更新顺序和在子组件的声明顺序是一样的。先声明的先更新,后声明的后更新。
1. @State装饰器 - 组件内状态
- 是私有的,只能从组件内部访问。
- 在声明时 必须指定其类型和本地初始化。
- 与子组件中的 @Prop,@Link、@ObjectLink装饰变量之间建立双向数据同步。
- 允许装饰的类型:string、number、boolean、object、class 和 enum类型,以及这些类型的数组。
- 并不是@State状态变量的所有更改都会引起UI刷新,只有可以被框架观察到的修改才会引起UI刷新。
- 框架能够观察到的变化如下:
6.1 当@State装饰的变量类型为string、number、boolean类型时,可以观察到赋值的变化。
6.2 当@State装饰的变量类型为object、class类型时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为 object 或者 class 时,则嵌套属性的变化是观察不到的。
6.3 当@State装饰的变量类型为数组时,可以观察到数组本身赋值的变化,和其元素的添加、删除及更新的变化,若元素类型为 object 或者 class 时,元素属性的变化是观察不到的。
// 自定义类型
class Person {
public name: string
public age: number
constructor(xName: string, xAge: number) {
this.name = xName
this.age = xAge
}
}
// 自定义子组件
@Component
struct MyChild {
@State person: Person = new Person('魔鬼', 18) // 指定自定义类型,初始化值
private increase: number = 1
build() {
Column({space: 3}) {
Text(`${this.person.name}、年龄${this.person.age}`).fontSize(18).fontWeight(500).height(60)
Divider()
Button(`修改姓名`).onClick(() => {
this.person.name = this.person.name === '魔鬼' ? '天使': '魔鬼'
})
.width(200)
.height(60)
Button('修改年龄').onClick(() => {
this.person.age += this.increase
})
.width(200)
.height(60)
}
// .backgroundColor('#CCBBFF')
}
}
// 父组件
@Entry
@Component
struct UITest5 {
build() {
Column({space: 30}) {
MyChild({person: new Person('天使', 2), increase: 1})
MyChild({increase: 2})
MyChild()
}
}
}
2. @Prop装饰器 - 父子单向同步
- @Prop装饰器不能在@Entry装饰的自定义组件中使用。
- 被装饰变量的初始值,允许本地初始化。
- 允许装饰的类型:string、number、boolean 和 enum类型,注意不支持 class、object 和数组。
- 框架能够观察到的变化如下:
4.1 当@Prop装饰的类型是允许的类型,所有赋值的变化都可以观察到。
// @Prop装饰器 - 父子单向同步
// 子组件
@Component
struct MyChild {
@Prop age: number = 9 // 被装饰变量的初始值,允许本地初始化。当没有初始值时,页面显示undefined
private increase: number = 1
build() {
Column(){
if (this.age >= 18) {
Text(`子组件年龄${this.age}`).height(60)
} else {
Text(`未成年${this.age}`).height(60)
}
Button('减少子组件年龄').onClick(() => {
this.age -= this.increase
})
}
}
}
// 父组件
@Entry
@Component
struct UITest6{
@State init_age: number = 14
build() {
Column() {
Text(`父组件年龄${this.init_age}`).height(60)
Button('增加父组件年龄').onClick(() => {
this.init_age += 1
})
Divider()
MyChild({age: this.init_age, increase: 2})
Divider()
MyChild()
}
}
}
3. @Link装饰器 - 父子双向同步
- 父组件中@State、@StorageLink、@Link 和 子组件@Link可以建立双向数据同步。
- 被装饰变量的初始值,禁止本地初始化。
- 父组件必须用
$变量名
的方式传参,表示传递的是变量的引用。- 允许装饰的类型:string、number、boolean、object、class 和 enum类型,以及这些类型的数组。(同@State)
- 框架能够观察到的变化如下:(同@State)
5.1 当@State装饰的变量类型为string、number、boolean类型时,可以观察到赋值的变化。
5.2 当@State装饰的变量类型为object、class类型时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为 object 或者 class 时,则嵌套属性的变化是观察不到的。
5.3 当@State装饰的变量类型为数组时,可以观察到数组本身赋值的变化,和其元素的添加、删除及更新的变化,若元素类型为 object 或者 class 时,元素属性的变化是观察不到的。
下面代码展示了class类对象类型、简单类型,俩种父子双向数据同步示例。
// @Link装饰器 - 父子双向同步。class类对象类型和简单类型俩种父子双向同步
// 自定义class类对象类型
class ButtonState {
value: string
width: number
constructor(value: string, width: number) {
this.value = value
this.width = width
}
}
// 一号子组件 - class类对象类型
@Component
struct MyChildButton01 {
// class类对象类型
@Link buttonState: ButtonState
build() {
Column() {
Button(`${this.buttonState.value}${this.buttonState.width}`)
.width(this.buttonState.width)
.height(50)
.backgroundColor('#B088FF')
.fontColor('#FFFFFF,90%')
.onClick(() => {
if (this.buttonState.width < 400) {
this.buttonState.width += 50
} else {
this.buttonState = new ButtonState('一号本地', 100)
}
})
}
}
}
// 二号子组件 - 简单类型
@Component
struct MyChildButton02 {
// 简单类型
@Link buttonValue: string
@Link buttonWidth: number
build() {
Column() {
Button(`${this.buttonValue}${this.buttonWidth}`)
.width(this.buttonWidth)
.height(50)
.backgroundColor('#FF7744')
.fontColor('#FFFFFF,90%')
.onClick(() => {
this.buttonValue = this.buttonWidth < 400 ? this.buttonValue : '二号本地'
this.buttonWidth = this.buttonWidth < 400 ? this.buttonWidth + 50 : 100
})
}
}
}
// 父组件
@Entry
@Component
struct UITest6 {
// class类对象类型
@State parentButton: ButtonState = new ButtonState('一号子级', 100)
// 简单类型
@State parentValue: string = '二号子级'
@State parentWidth: number = 100
build() {
Column({space: 10}) {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
// class类对象类型从父组件@State向子组件@Link数据同步
Button(`父组件中修改${this.parentButton.value}:${this.parentButton.width}`).onClick(() => {
this.parentButton.width = this.parentButton.width < 400 ? this.parentButton.width + 50 : 100
})
// 简单类型从父组件@State向子组件@Link数据同步
Button(`父组件中修改${this.parentValue}:${this.parentWidth}`).onClick(() => {
this.parentWidth = this.parentWidth < 400 ? this.parentWidth + 50 : 100
})
// class类对象类型初始化@Link
MyChildButton01({ buttonState: $parentButton })
// 简单类型初始化@Link
MyChildButton02({ buttonValue: $parentValue, buttonWidth: $parentWidth })
}
}
}
}
4. @Provide装饰器、@Consume装饰器 - 与后代组件双向同步
- 用于跨组件层级传递状态信息,其中 @Provide 用于装饰祖先组件的状态变量, @Consume 用于装饰后代组件的状态变量。并且状态信息可以实现双向同步。
- @Provide装饰的变量必须进行本地初始化;@Consume装饰的变量不允许进行本地初始化。
- @Provide 和 @Consume 装饰的变量不是通过父组件向子组件传参的方式进行绑定的,而是通过相同的变量名进行绑定的。
- 除了通过变量名进行绑定,还可通过变量的别名进行绑定。
- 允许装饰的类型:string、number、boolean、object、class 和 enum类型,以及这些类型的数组。(同@State)
- 框架能够观察到的变化如下:(同@State)
6.1 当@State装饰的变量类型为string、number、boolean类型时,可以观察到赋值的变化。
6.2 当@State装饰的变量类型为object、class类型时,可以观察到变量自身赋值的变化,和其属性赋值的变化。需要注意的是,若某个属性也为 object 或者 class 时,则嵌套属性的变化是观察不到的。
6.3 当@State装饰的变量类型为数组时,可以观察到数组本身赋值的变化,和其元素的添加、删除及更新的变化,若元素类型为 object 或者 class 时,元素属性的变化是观察不到的。
5. @Observed装饰器、@ObjectLink装饰器 - 嵌套类对象属性变化
- @Observed装饰器 装饰类型的定义
- @ObjectLink装饰器 装饰状态变量