1. @Prop 父子单向同步
概述
@Prop装饰的变量和父组件建立单向的同步关系:
- @Prop变量允许在本地修改,但修改后的变化不会同步回父组件。
- 当父组件中的数据源更改时,与之相关的@Prop装饰的变量都会自动更新。如果子组件已经在本地修改了@Prop装饰的相关变量值,而在父组件中对应的@State装饰的变量被修改后,子组件本地修改的@Prop装饰的相关变量值将被覆盖。
装饰器使用规则说明
@Prop变量装饰器 | 说明 |
---|---|
装饰器参数 | 无 |
同步类型 | 单向同步:对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,子组件@Prop变量的修改不会同步到父组件的状态变量上 |
允许装饰的变量类型 | string、number、boolean、enum类型。 不支持any,不允许使用undefined和null。 必须指定类型。 在父组件中,传递给@Prop装饰的值不能为undefined或者null,反例如下所示。 CompA ({ aProp: undefined }) CompA ({ aProp: null }) @Prop和数据源类型需要相同,有以下三种情况(数据源以@State为例):
|
被装饰变量的初始值 | 允许本地初始化。 |
示例
@Entry
@Component
struct Index {
@State num: number = 10
build() {
Column() {
Text(`Parent -- ${this.num}`)
Button("增加Num的值").onClick(() => {
this.num++
})
Child({ num: this.num })
}
.width('100%')
.height('100%')
}
}
@Component
struct Child {
@Prop num: number
build() {
Column() {
Text(`Child -- ${this.num}`)
Button("子元素 增加Num的值").onClick(() => {
this.num++
})
}
.width('100%')
.height(100)
.backgroundColor(Color.Pink)
}
}
2. @Link 父子双向同步
概述
@Link装饰的变量与其父组件中的数据源共享相同的值。
装饰器使用规则说明
@Link变量装饰器 | 说明 |
---|---|
装饰器参数 | 无 |
同步类型 | 双向同步。 父组件中@State, @StorageLink和@Link 和子组件@Link可以建立双向数据同步,反之亦然。 |
允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考观察变化。 类型必须被指定,且和双向绑定状态变量的类型相同。 不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。 说明 不支持Length、ResourceStr、ResourceColor类型,Length、ResourceStr、ResourceColor为简单类型和复杂类型的联合类型。 |
被装饰变量的初始值 | 无,禁止本地初始化。 |
示例
在父组件中传递值时,需要使用 $ 来引用子组件中被 @Link 修饰的数据。
简单类型 string、number、boolean、enum
@Entry
@Component
struct Index {
@State num: number = 10
build() {
Column() {
Text(`${this.num}`)
Button("增加Num的值").onClick(() => {
this.num++
})
Child({ num: $num })
}
.width('100%')
.height('100%')
}
}
@Component
struct Child {
@Link num: number
build() {
Column() {
Text(`${this.num}`)
Button("子元素 增加Num的值").onClick(() => {
this.num++
})
}
.width('100%')
.height(100)
.backgroundColor(Color.Pink)
}
}
复杂类型 Object、class
class Person {
name: string = ""
age: number = 0
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
@Entry
@Component
struct Index {
@State p: Person = { name: "lili", age: 18 }
build() {
Column() {
Text(`${this.p.name}--${this.p.age}`)
Button("增加age的值").onClick(() => {
this.p.age++
})
Child({ p: $p })
}
.width('100%')
.height('100%')
}
}
@Component
struct Child {
@Link p: Person
build() {
Column() {
Text(`${this.p.name}--${this.p.age}`)
Button("子元素 增加age的值").onClick(() => {
this.p.age++
})
}
.width('100%')
.height(100)
.backgroundColor(Color.Pink)
}
}
3. @Provide / @Consume 后代组件双向同步
概述
@Provide/@Consume装饰的状态变量有以下特性:
- @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。
- 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递。
- @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同。
// 通过相同的变量名绑定
@Provide a: number = 0;
@Consume a: number;
// 通过相同的变量别名绑定
@Provide('a') b: number = 0;
@Consume('a') c: number;
@Provide和@Consume通过相同的变量名或者相同的变量别名绑定时,@Provide修饰的变量和@Consume修饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的@Provide装饰的变量。
装饰器使用规则说明
@State的规则同样适用于@Provide,差异为@Provide还作为多层后代的同步源。
@Provide变量装饰器 | 说明 |
---|---|
装饰器参数 | 别名:常量字符串,可选。 如果指定了别名,则通过别名来绑定变量;如果未指定别名,则通过变量名绑定变量。 |
同步类型 | 双向同步。 从@Provide变量到所有@Consume变量以及相反的方向的数据同步。双向同步的操作与@State和@Link的组合相同。 |
允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考观察变化。 不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。 必须指定类型。@Provide变量的@Consume变量的类型必须相同。 说明 不支持Length、ResourceStr、ResourceColor类型,Length、ResourceStr、ResourceColor为简单类型和复杂类型的联合类型。 |
被装饰变量的初始值 | 必须指定。 |
@Consume变量装饰器 | 说明 |
---|---|
装饰器参数 | 别名:常量字符串,可选。 如果提供了别名,则必须有@Provide的变量和其有相同的别名才可以匹配成功;否则,则需要变量名相同才能匹配成功。 |
同步类型 | 双向:从@Provide变量(具体请参见@Provide)到所有@Consume变量,以及相反的方向。双向同步操作与@State和@Link的组合相同。 |
允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考观察变化。 不支持any,不允许使用undefined和null。 必须指定类型。@Provide变量的@Consume变量的类型必须相同。 说明
|
被装饰变量的初始值 | 无,禁止本地初始化。 |
示例
class Person {
name: string = ""
age: number = 0
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
@Entry
@Component
struct Index {
@Provide p: Person = { name: "lili", age: 18 }
build() {
Column() {
Text(`祖先`)
Text(`${this.p.name}--${this.p.age}`)
Button("增加age的值").onClick(() => {
this.p.age++
})
Parent()
}
.width('100%')
.height('100%')
}
}
@Component
struct Parent {
build() {
Column() {
Text(`父级`)
Child()
}
.width('100%')
.height(300)
.backgroundColor(Color.Pink)
}
}
@Component
struct Child {
@Consume p: Person
build() {
Column() {
Text(`后代`)
Text(`${this.p.name}--${this.p.age}`)
Button("子元素 增加age的值").onClick(() => {
this.p.age++
})
}
.width('100%')
.height(200)
.backgroundColor(Color.Orange)
}
}
4. @Observed / @ObjectLink 嵌套类对象属性变化
概述
@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:
- 被@Observed装饰的类,可以被观察到属性的变化;
- 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
- 单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。
装饰器使用规则说明
@Observed类装饰器 | 说明 |
---|---|
装饰器参数 | 无 |
类装饰器 | 装饰class。需要放在class的定义前,使用new创建类对象。 |
@ObjectLink变量装饰器 | 说明 |
---|---|
装饰器参数 | 无 |
同步类型 | 不与父组件中的任何类型同步变量。 |
允许装饰的变量类型 | 必须为被@Observed装饰的class实例,必须指定类型。 不支持简单类型,可以使用@Prop。 @ObjectLink的属性是可以改变的,但是变量的分配是不允许的,也就是说这个装饰器装饰变量是只读的,不能被改变。 |
被装饰变量的初始值 | 不允许。 |
示例
@Observed
class BookItem {
id: number = 0
name: string = ""
size: number = 0
constructor(id: number, name: string, size: number) {
this.id = id
this.name = name
this.size = size
}
}
@Entry
@Component
struct Index {
@State bookArr: BookItem[] = [
new BookItem(1, "Java", 10),
new BookItem(2, "ArkTS", 20)
]
build() {
Column({ space: 10 }) {
Text(`${JSON.stringify(this.bookArr)}`)
Text(`${JSON.stringify(this.bookArr[0].size)}`)
//注意:子组件页面数据是更新的,父组件页面数据未更新
//原因:数据本身是更新的,父组件页面不在重新渲染,子组件页面重新渲染
Button("修改Size").onClick(() => {
this.bookArr[0].size += 1
//修改数据的方法1 重新赋值 解构赋值和展开运算 (Next不能用了)
//this.bookArr[0] = { ...this.bookArr[0], size:30 }
//修改数据的方法2 重新赋值
// const book = this.bookArr[0]
// this.bookArr[0] = new BookItem(book.id, book.name, 30)
})
ForEach(this.bookArr,
(item) => {
Child({ item })
},
(item) => JSON.stringify(item)
)
}
.width('100%')
.height('100%')
}
}
@Component
struct Child {
@ObjectLink item: BookItem
build() {
Column() {
Text(`${JSON.stringify(this.item)}`)
Text(`${JSON.stringify(this.item.size)}`)
Button("子元素---修改Size").onClick(() => {
this.item.size += 1
})
}
.width('100%')
.height('100')
.backgroundColor(Color.Pink)
}
}