官方文档:@Prop装饰器:父子单向同步
[Q&A] @Prop装饰器作用
@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。
[Q&A] @Prop装饰器特点
1・@Prop装饰器不能在@Entry装饰的自定义组件中使用。
2・@Prop装饰变量时会进行深拷贝,在拷贝的过程中除了基本类型、Map、Set、Date、Array外,都会丢失类型。
样例1:Date
@Component
struct DateComponent {
@Prop childSelectedDate: Date = new Date('');
build() {
Column() {
Row() {
Button('child +1年').margin(5).width('30%')
.onClick(() => {
this.childSelectedDate.setFullYear(this.childSelectedDate.getFullYear() + 1)
})
Button('child +1月').margin(5).width('30%')
.onClick(() => {
this.childSelectedDate.setMonth(this.childSelectedDate.getMonth() + 1)
})
Button('child +1天').margin(5).width('30%')
.onClick(() => {
this.childSelectedDate.setDate(this.childSelectedDate.getDate() + 1)
})
}.width('100%')
Button('child 重置日期').margin(10).width('100%')
.onClick(() => {
this.childSelectedDate = new Date('2023-07-07')
})
DatePicker({
start: new Date('1970-1-1'),
end: new Date('2100-1-1'),
selected: this.childSelectedDate
})
}
}
}
@Entry
@Component
struct SizeExample {
@State parentSelectedDate: Date = new Date('2008-08-08');
build() {
Column() {
Row() {
Button('parent +1年').margin(5).width('30%')
.onClick(() => {
this.parentSelectedDate.setFullYear(this.parentSelectedDate.getFullYear() + 1)
})
Button('parent +1月').margin(5).width('30%')
.onClick(() => {
this.parentSelectedDate.setMonth(this.parentSelectedDate.getMonth() + 1)
})
Button('parent +1天').margin(5).width('30%')
.onClick(() => {
this.parentSelectedDate.setDate(this.parentSelectedDate.getDate() + 1)
})
}.width('100%')
Button('parent 重置日期').margin(10).width('100%')
.onClick(() => {
this.parentSelectedDate = new Date('2023-07-07')
})
DatePicker({
start: new Date('1970-1-1'),
end: new Date('2100-1-1'),
selected: this.parentSelectedDate
})
DateComponent({ childSelectedDate: this.parentSelectedDate })
}
}
}
样例2:父组件@State简单数据类型→子组件@Prop简单数据类型同步
@Component
struct CountDownComponent {
@Prop count: number = 0;
costOfOneAttempt: number = 1;
build() {
Row() {
if (this.count > 0) {
Text(`当前值为 ${this.count} .`).fontSize(20).margin(10).textAlign(TextAlign.Center)
} else {
Text('Game over!').fontSize(20).margin(10)
}
Button('子 -1').onClick(() => {
this.count -= this.costOfOneAttempt;
}).width("40%")
}.width('100%')
}
}
@Entry
@Component
struct SizeExample {
@State countDownStartValue: number = 10;
build() {
Column() {
Row() {
if (this.countDownStartValue > 0) {
Text(`当前值为 ${this.countDownStartValue} .`).fontSize(20).margin(5).textAlign(TextAlign.Center)
} else {
Text('Game over!').fontSize(20).margin(10)
}
Button('父 +1 ').onClick(() => {
this.countDownStartValue += 1;
}).margin(5).width("20%")
Button('父 -1 ').onClick(() => {
this.countDownStartValue -= 1;
}).margin(5).width("20%")
}.width('100%')
CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
}
}
}
样例3:父组件@State数组项→子组件@Prop简单数据类型同步
@Component
struct Child {
@Prop value: number = 0;
build() {
Text(`${this.value}`).fontSize(30)
.onClick(() => {
this.value++
})
}
}
@Entry
@Component
struct SizeExample {
@State arr: number[] = [1, 2, 3];
build() {
Row() {
Column() {
Text(`当前值为 ${this.arr[0]},${this.arr[1]},${this.arr[2]}.`).fontSize(30).margin(10).textAlign(TextAlign.Center)
Divider().height(10)
Row() {
Child({ value: this.arr[0] }).width('30%').align(Alignment.Center).backgroundColor(Color.Red)
Child({ value: this.arr[1] }).width('30%').align(Alignment.Center).backgroundColor(Color.Green)
Child({ value: this.arr[2] }).width('30%').align(Alignment.Center).backgroundColor(Color.Yellow)
}.alignItems(VerticalAlign.Center)
Divider().height(10)
Row() {
ForEach(this.arr, (item: number) => {
Child({ value: item }).width('30%').align(Alignment.Center).backgroundColor(Color.Orange).border({ width: 1, style: BorderStyle.Dashed })
}, (item: string) => item.toString())
}.alignItems(VerticalAlign.Center)
Divider().height(10)
Text('重置').fontSize(30).backgroundColor(Color.Pink).width('50%').textAlign(TextAlign.Center).padding(10)
.onClick(() => {
// 两个数组都包含项“3”。
this.arr = this.arr[0] == 1 ? [3, 4, 5] : [1, 2, 3];
})
}
}
}
}
样例4:父组件@State类对象属性→@Prop简单类型的同步
class Book {
public title: string;
public pages: number;
public readIt: boolean = false;
constructor(title: string, pages: number) {
this.title = title;
this.pages = pages;
}
}
@Component
struct ReaderComp {
@Prop book: Book = new Book("", 0);
build() {
Row() {
Text(this.book.title).fontSize(20)
Text(` 有 ${this.book.pages} 页! `).fontSize(20)
Text(`${this.book.readIt ? " 我读了" : ' 我还没开始读'}`).fontSize(20)
.onClick(() => this.book.readIt = true).backgroundColor(Color.Pink)
}
}
}
@Entry
@Component
struct SizeExample {
@State book: Book = new Book('资治通鉴', 765);
build() {
Column() {
ReaderComp({ book: this.book })
ReaderComp({ book: this.book })
}
}
}
样例5:父组件@State数组项→@Prop class类型的同步
let nextId: number = 1;
@Observed // @Prop在子组件装饰的状态变量和父组件的数据源是单向同步关系,需要使用@Observed装饰class Book,Book的属性将被观察。
class Book {
public id: number;
public title: string;
public pages: number;
public readIt: boolean = false;
constructor(title: string, pages: number) {
this.id = nextId++;
this.title = title;
this.pages = pages;
}
}
@Component
struct ReaderComp {
@Prop book: Book = new Book("", 1);
build() {
Row() {
Text(` ${this.book ? this.book.title : "未定义"}`).fontColor(Color.Red)
Text(` 有 ${this.book ? this.book.pages : "未定义"} 页!`).fontColor(Color.Black)
Text(` ${this.book ? (this.book.readIt ? "我已经读了" : '我还没读' ): "未定义"}`).fontColor(Color.Blue)
.onClick(() => this.book.readIt = true)
}
}
}
@Entry
@Component
struct SizeExample {
@State allBooks: Book[] = [new Book("资治通鉴", 100), new Book("史记", 100), new Book("论语", 100)];
build() {
Column() {
Text('畅销书').width(312).height(40).fontSize(20).margin(12).fontColor('#e6000000')
ReaderComp({ book: this.allBooks[2] }).backgroundColor('#0d000000').width(312).height(40).padding({ left: 20, top: 10 }).borderRadius(20).colorBlend('#e6000000')
Divider()
Text('已经购买的书').width(312).height(40).fontSize(20).margin(12).fontColor('#e6000000')
ForEach(this.allBooks, (book: Book) => {
ReaderComp({ book: book }).margin(12).width(312).height(40).padding({ left: 20, top: 10 }).backgroundColor('#0d000000').borderRadius(20)
},(book: Book) => book.id.toString())
Button('追加').width(312).height(40).margin(12).fontColor('#FFFFFF 90%')
.onClick(() => {
this.allBooks.push(new Book("孟子", 100));
})
Button('移除第一本书').width(312).height(40).margin(12).fontColor('#FFFFFF 90%')
.onClick(() => {
if (this.allBooks.length > 0){
this.allBooks.shift();
} else {
console.log("length <= 0")
}
})
Button("所有人都已经读了").width(312).height(40).margin(12).fontColor('#FFFFFF 90%')
.onClick(() => {
this.allBooks.forEach((book) => book.readIt = true)
})
}
}
}