1.@Prop和@Link
当父子组件之间需要数据同步时,可以使用@Prop和@Link装饰器:
(1)@Prop
@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。
@Entry
@Component
struct Index {
@State grade:number = 59
build() {
Column() {
GradeShow({grade:this.grade})
EvaluateShow({grade:this.grade})
Button('父布局改变')
.onClick(()=>{
this.grade++
})
}.width('100%')
}
}
@Component
struct GradeShow {
@Prop grade:number
build() {
Column() {
Text(`当前的分数:${this.grade}`)
Button('独自改变')
.onClick(()=>{
this.grade++
})
}
}
}
@Component
struct EvaluateShow {
@Prop grade:number
build() {
if(this.grade<60) {
Text('您不及格哦')
} else if(this.grade<70) {
Text('你及格了')
} else if(this.grade<80) {
Text('一般')
} else if(this.grade<90) {
Text('良好')
} else {
Text('优秀')
}
}
}
效果如上,如果点击“独立改变”呢,只会改变第一个子View的显示,并不能改变父组件内grade的值;如果点击的是“父布局改变”,grade发生变化,子组件发生变化。因为,@Prop是父向子建立单向的关系。
(2)@Link
子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。
class Hobby {
name: string
constructor(name: string) {
this.name = name
}
}
interface GirlFriend {
name:string,
age:number
}
@Component
struct HobbyChild {
@Prop hobby:Hobby
@Prop gf:GirlFriend
build() {
Text(`兴趣:${this.hobby.name},女友:${this.gf.name},年纪:${this.gf.age}`)
}
}
@Entry
@Component
struct Index {
@State all: number = 0
@State current: number = 0
@State hobby:Hobby = new Hobby('Ball')
@State gf:GirlFriend = {
name:'Rose',
age:18
}
build() {
Column() {
TaskProcess({ all: this.all, current: this.current })
TaskCard({ all: $all, current: $current })
HobbyChild({hobby:this.hobby,gf:this.gf})
Button('改变爱好')
.onClick(()=>{
this.hobby.name = 'book'
this.gf.age = 20
})
}.width('100%')
}
}
interface Task {
name: string,
chosen: boolean
}
@Component
struct TaskProcess {
@Prop current: number
@Prop all: number
build() {
Text(`${this.current}/${this.all}`)
}
}
@Component
struct TaskCard {
@Link current: number
@Link all: number
@State taskList: Array<Task> = []
build() {
Column() {
Button('添加任务')
.onClick(() => {
this.taskList.push({
name: `第${this.taskList.length}个任务`,
chosen: false
})
this.current = this.taskList.filter((item) => item.chosen).length
this.all = this.taskList.length
})
ForEach(this.taskList, (item: Task) => {
Row() {
Text(item.name)
Checkbox()
.select(item.chosen)
.onChange((value) => {
item.chosen = value
this.current = this.taskList.filter((item) => item.chosen).length
})
}.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.padding({
left: 20,
right: 20
})
})
}.width('100%')
}
}
2.@Prophe和和@Link支持的数据类型
(1)@Prop
支持Object、class、string、number、boolean、enum类型,以及这些类型的数组。
不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。
支持Date类型。
不允许子组件初始化。
(2)@Link
支持Object、class、string、number、boolean、enum类型,以及这些类型的数组。
支持Date类型。
类型必须被指定,且和双向绑定状态变量的类型相同。
不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。
父组件传递,禁止子组件初始化。
3.@Providehe和@Consume
可以跨组件提供类似于@State和@Link的双向同步。我们改造一下上述的例子:
class Hobby {
name: string
constructor(name: string) {
this.name = name
}
}
interface GirlFriend {
name:string,
age:number
}
@Component
struct HobbyChild {
@Prop hobby:Hobby
@Prop gf:GirlFriend
build() {
Text(`兴趣:${this.hobby.name},女友:${this.gf.name},年纪:${this.gf.age}`)
}
}
class TaskInfo {
all:number = 0
current:number = 0
}
@Entry
@Component
struct Index {
@Provide taskInfo:TaskInfo = new TaskInfo()
@State hobby:Hobby = new Hobby('Ball')
@State gf:GirlFriend = {
name:'Rose',
age:18
}
build() {
Column() {
TaskProcess()
TaskCard()
HobbyChild({hobby:this.hobby,gf:this.gf})
Button('改变爱好')
.onClick(()=>{
this.hobby.name = 'book'
this.gf.age = 20
})
}.width('100%')
}
}
interface Task {
name: string,
chosen: boolean
}
@Component
struct TaskProcess {
@Consume taskInfo:TaskInfo
build() {
Text(`${this.taskInfo.current}/${this.taskInfo.all}`)
}
}
@Component
struct TaskCard {
@Consume taskInfo:TaskInfo
@State taskList: Array<Task> = []
build() {
Column() {
Button('添加任务')
.onClick(() => {
this.taskList.push({
name: `第${this.taskList.length}个任务`,
chosen: false
})
this.taskInfo.current = this.taskList.filter((item) => item.chosen).length
this.taskInfo.all = this.taskList.length
})
ForEach(this.taskList, (item: Task) => {
Row() {
Text(item.name)
Checkbox()
.select(item.chosen)
.onChange((value) => {
item.chosen = value
this.taskInfo.current = this.taskList.filter((item) => item.chosen).length
})
}.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.padding({
left: 20,
right: 20
})
})
}.width('100%')
}
}
@Provide和@Consume能跨组件使用,不用显示传参,必然会带来一些资源上的损耗。在不用跨组件通信的场景下,我们还是尽量使用@Prop和@Link。