@Prop裝飾的變量可以和父組件建立單向的同步關(guān)系。@Prop裝飾的變量是可變的毙驯,但是變化不會(huì)同步回其父組件回右。
說明:
從API version 9開始供璧,該裝飾器支持在ArkTS卡片中使用。
概述
@Prop裝飾的變量和父組件建立單向的同步關(guān)系:
@Prop變量允許在本地修改熏迹,但修改后的變化不會(huì)同步回父組件。
當(dāng)數(shù)據(jù)源更改時(shí),@Prop裝飾的變量都會(huì)更新受啥,并且會(huì)覆蓋本地所有更改。因此鸽心,數(shù)值的同步是父組件到子組件(所屬組件)滚局,子組件數(shù)值的變化不會(huì)同步到父組件。
限制條件
@Prop裝飾變量時(shí)會(huì)進(jìn)行深拷貝顽频,在拷貝的過程中除了基本類型藤肢、Map、Set糯景、Date嘁圈、Array外,都會(huì)丟失類型蟀淮。例如PixelMap 等通過NAPI提供的復(fù)雜類型最住,由于有部分實(shí)現(xiàn)在Native側(cè),因此無法在ArkTS側(cè)通過深拷貝獲得完整的數(shù)據(jù)怠惶。
@Prop裝飾器不能在@Entry裝飾的自定義組件中使用涨缚。
裝飾器使用規(guī)則說明
@Prop變量裝飾器 | 說明 |
---|---|
裝飾器參數(shù) | 無 |
同步類型 | 單向同步:對(duì)父組件狀態(tài)變量值的修改,將同步給子組件@Prop裝飾的變量策治,子組件@Prop變量的修改不會(huì)同步到父組件的狀態(tài)變量上脓魏。嵌套類型的場景請(qǐng)參考 觀察變化 。 |
允許裝飾的變量類型 | Object通惫、class茂翔、string、number履腋、boolean珊燎、enum類型,以及這些類型的數(shù)組府树。 不支持any俐末,支持undefined和null。 支持Date類型奄侠。 API11及以上支持Map卓箫、Set類型。 支持類型的場景請(qǐng)參考 觀察變化 垄潮。 API11及以上支持上述支持類型的聯(lián)合類型烹卒,比如string | number, string | undefined 或者 ClassA | null闷盔,示例見 Prop支持聯(lián)合類型實(shí)例 。 注意 當(dāng)使用undefined和null的時(shí)候旅急,建議顯式指定類型逢勾,遵循TypeScipt類型校驗(yàn),比如: @Prop a : string | undefined = undefined 是推薦的藐吮,不推薦@Prop a: string = undefined 溺拱。 |
支持AkrUI框架定義的聯(lián)合類型Length、ResourceStr谣辞、ResourceColor類型迫摔。 | 必須指定類型。 @Prop和 數(shù)據(jù)源 類型需要相同泥从,有以下三種情況: -?@Prop裝飾的變量和@State以及其他裝飾器同步時(shí)雙方的類型必須相同句占,示例請(qǐng)參考 父組件@State到子組件@Prop簡單數(shù)據(jù)類型同步 。 -?@Prop裝飾的變量和@State以及其他裝飾器裝飾的數(shù)組的項(xiàng)同步時(shí) 躯嫉,@Prop的類型需要和@State裝飾的數(shù)組的數(shù)組項(xiàng)相同纱烘,比如@Prop?:?T和@State?:?Array<T>,示例請(qǐng)參考 父組件@State數(shù)組中的項(xiàng)到子組件@Prop簡單數(shù)據(jù)類型同步 祈餐。 -?當(dāng)父組件狀態(tài)變量為Object或者class時(shí)擂啥,@Prop裝飾的變量和父組件狀態(tài)變量的屬性類型相同,示例請(qǐng)參考 從父組件中的@State類對(duì)象屬性到@Prop簡單類型的同步 昼弟。 |
嵌套傳遞層數(shù) | 在組件復(fù)用場景啤它,建議@Prop深度嵌套數(shù)據(jù)不要超過5層,嵌套太多會(huì)導(dǎo)致深拷貝占用的空間過大以及GarbageCollection(垃圾回收)舱痘,引起性能問題变骡,此時(shí)更建議使用 @ObjectLink 。 |
被裝飾變量的初始值 | 允許本地初始化芭逝。如果在API 11中和 @Require 結(jié)合使用塌碌,則必須父組件構(gòu)造傳參。 |
變量的傳遞/訪問規(guī)則說明
傳遞/訪問 | 說明 |
---|---|
從父組件初始化 | 如果本地有初始化旬盯,則是可選的台妆。沒有的話,則必選胖翰,支持父組件中的常規(guī)變量(常規(guī)變量對(duì)@Prop賦值接剩,只是數(shù)值的初始化,常規(guī)變量的變化不會(huì)觸發(fā)UI刷新萨咳。只有狀態(tài)變量才能觸發(fā)UI刷新)懊缺、@State、@Link培他、@Prop鹃两、@Provide遗座、@Consume、@ObjectLink俊扳、@StorageLink途蒋、@StorageProp、@LocalStorageLink和@LocalStorageProp去初始化子組件中的@Prop變量馋记。 |
用于初始化子組件 | @Prop支持去初始化子組件中的常規(guī)變量号坡、@State、@Link抗果、@Prop筋帖、@Provide奸晴。 |
是否支持組件外訪問 | @Prop裝飾的變量是私有的冤馏,只能在組件內(nèi)訪問。 |
圖1 初始化規(guī)則圖示
觀察變化和行為表現(xiàn)
觀察變化
@Prop裝飾的數(shù)據(jù)可以觀察到以下變化寄啼。
-
當(dāng)裝飾的類型是允許的類型逮光,即Object、class墩划、string涕刚、number、boolean乙帮、enum類型都可以觀察到賦值的變化杜漠。
// 簡單類型 @Prop count: number; // 賦值的變化可以被觀察到 this.count = 1; // 復(fù)雜類型 @Prop title: Model; // 可以觀察到賦值的變化 this.title = new Model('Hi');
當(dāng)裝飾的類型是Object或者class復(fù)雜類型時(shí),可以觀察到第一層的屬性的變化察净,屬性即Object.keys(observedObject)返回的所有屬性驾茴;
class ClassA {
public value: string;
constructor(value: string) {
this.value = value;
}
}
class Model {
public value: string;
public a: ClassA;
constructor(value: string, a: ClassA) {
this.value = value;
this.a = a;
}
}
@Prop title: Model;
// 可以觀察到第一層的變化
this.title.value = 'Hi'
// 觀察不到第二層的變化
this.title.a.value = 'ArkUi'
對(duì)于嵌套場景,如果class是被@Observed裝飾的氢卡,可以觀察到class屬性的變化锈至,示例請(qǐng)參考@Prop嵌套場景。
- 當(dāng)裝飾的類型是數(shù)組的時(shí)候译秦,可以觀察到數(shù)組本身的賦值和數(shù)組項(xiàng)的添加峡捡、刪除和更新。
// @State裝飾的對(duì)象為數(shù)組時(shí)
@Prop title: string[]
// 數(shù)組自身的賦值可以觀察到
this.title = ['1']
// 數(shù)組項(xiàng)的賦值可以觀察到
this.title[0] = '2'
// 刪除數(shù)組項(xiàng)可以觀察到
this.title.pop()
// 新增數(shù)組項(xiàng)可以觀察到
this.title.push('3')
對(duì)于@State和@Prop的同步場景:
使用父組件中@State變量的值初始化子組件中的@Prop變量筑悴。當(dāng)@State變量變化時(shí)们拙,該變量值也會(huì)同步更新至@Prop變量。
@Prop裝飾的變量的修改不會(huì)影響其數(shù)據(jù)源@State裝飾變量的值阁吝。
除了@State砚婆,數(shù)據(jù)源也可以用@Link或@Prop裝飾,對(duì)@Prop的同步機(jī)制是相同的求摇。
數(shù)據(jù)源和@Prop變量的類型需要相同射沟,@Prop允許簡單類型和class類型殊者。
當(dāng)裝飾的對(duì)象是Date時(shí),可以觀察到Date整體的賦值验夯,同時(shí)可通過調(diào)用Date的接口
setFullYear
,setMonth
,setDate
,setHours
,setMinutes
,setSeconds
,setMilliseconds
,setTime
,setUTCFullYear
,setUTCMonth
,setUTCDate
,setUTCHours
,setUTCMinutes
,setUTCSeconds
,setUTCMilliseconds
更新Date的屬性猖吴。
@Component
struct DateComponent {
@Prop selectedDate: Date = new Date('');
build() {
Column() {
Button('child update the new date')
.margin(10)
.onClick(() => {
this.selectedDate = new Date('2023-09-09')
})
Button(`child increase the year by 1`).onClick(() => {
this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1)
})
DatePicker({
start: new Date('1970-1-1'),
end: new Date('2100-1-1'),
selected: this.selectedDate
})
}
}
}
@Entry
@Component
struct ParentComponent {
@State parentSelectedDate: Date = new Date('2021-08-08');
build() {
Column() {
Button('parent update the new date')
.margin(10)
.onClick(() => {
this.parentSelectedDate = new Date('2023-07-07')
})
Button('parent increase the day by 1')
.margin(10)
.onClick(() => {
this.parentSelectedDate.setDate(this.parentSelectedDate.getDate() + 1)
})
DatePicker({
start: new Date('1970-1-1'),
end: new Date('2100-1-1'),
selected: this.parentSelectedDate
})
DateComponent({ selectedDate: this.parentSelectedDate })
}
}
}
當(dāng)裝飾的變量是Map時(shí),可以觀察到Map整體的賦值挥转,同時(shí)可通過調(diào)用Map的接口
set
,clear
,delete
更新Map的值海蔽。當(dāng)裝飾的變量是Set時(shí),可以觀察到Set整體的賦值绑谣,同時(shí)可通過調(diào)用Set的接口
add
,clear
,delete
更新Set的值党窜。
框架行為
要理解@Prop變量值初始化和更新機(jī)制,有必要了解父組件和擁有@Prop變量的子組件初始渲染和更新流程借宵。
-
初始渲染:
- 執(zhí)行父組件的build()函數(shù)將創(chuàng)建子組件的新實(shí)例幌衣,將數(shù)據(jù)源傳遞給子組件;
- 初始化子組件@Prop裝飾的變量壤玫。
-
更新:
- 子組件@Prop更新時(shí)豁护,更新僅停留在當(dāng)前子組件,不會(huì)同步回父組件欲间;
- 當(dāng)父組件的數(shù)據(jù)源更新時(shí)楚里,子組件的@Prop裝飾的變量將被來自父組件的數(shù)據(jù)源重置,所有@Prop裝飾的本地的修改將被父組件的更新覆蓋猎贴。
說明:
@Prop裝飾的數(shù)據(jù)更新依賴其所屬自定義組件的重新渲染班缎,所以在應(yīng)用進(jìn)入后臺(tái)后,@Prop無法刷新她渴,推薦使用@Link代替达址。
使用場景
父組件@State到子組件@Prop簡單數(shù)據(jù)類型同步
以下示例是@State到子組件@Prop簡單數(shù)據(jù)同步,父組件ParentComponent的狀態(tài)變量countDownStartValue初始化子組件CountDownComponent中@Prop裝飾的count惹骂,點(diǎn)擊“Try again”苏携,count的修改僅保留在CountDownComponent 不會(huì)同步給父組件ParentComponent。
ParentComponent的狀態(tài)變量countDownStartValue的變化將重置CountDownComponent的count对粪。
@Component
struct CountDownComponent {
@Prop count: number = 0;
costOfOneAttempt: number = 1;
build() {
Column() {
if (this.count > 0) {
Text(`You have ${this.count} Nuggets left`)
} else {
Text('Game over!')
}
// @Prop裝飾的變量不會(huì)同步給父組件
Button(`Try again`).onClick(() => {
this.count -= this.costOfOneAttempt;
})
}
}
}
@Entry
@Component
struct ParentComponent {
@State countDownStartValue: number = 10;
build() {
Column() {
Text(`Grant ${this.countDownStartValue} nuggets to play.`)
// 父組件的數(shù)據(jù)源的修改會(huì)同步給子組件
Button(`+1 - Nuggets in New Game`).onClick(() => {
this.countDownStartValue += 1;
})
// 父組件的修改會(huì)同步給子組件
Button(`-1 - Nuggets in New Game`).onClick(() => {
this.countDownStartValue -= 1;
})
CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
}
}
}
在上面的示例中:
CountDownComponent子組件首次創(chuàng)建時(shí)其@Prop裝飾的count變量將從父組件@State裝飾的countDownStartValue變量初始化右冻;
按“+1”或“-1”按鈕時(shí),父組件的@State裝飾的countDownStartValue值會(huì)變化著拭,這將觸發(fā)父組件重新渲染纱扭,在父組件重新渲染過程中會(huì)刷新使用countDownStartValue狀態(tài)變量的UI組件并單向同步更新CountDownComponent子組件中的count值;
更新count狀態(tài)變量值也會(huì)觸發(fā)CountDownComponent的重新渲染儡遮,在重新渲染過程中乳蛾,評(píng)估使用count狀態(tài)變量的if語句條件(this.count > 0),并執(zhí)行true分支中的使用count狀態(tài)變量的UI組件相關(guān)描述來更新Text組件的UI顯示;
當(dāng)按下子組件CountDownComponent的“Try again”按鈕時(shí)肃叶,其@Prop變量count將被更改蹂随,但是count值的更改不會(huì)影響父組件的countDownStartValue值;
父組件的countDownStartValue值會(huì)變化時(shí)因惭,父組件的修改將覆蓋掉子組件CountDownComponent中count本地的修改岳锁。
父組件@State數(shù)組項(xiàng)到子組件@Prop簡單數(shù)據(jù)類型同步
父組件中@State如果裝飾的數(shù)組,其數(shù)組項(xiàng)也可以初始化@Prop蹦魔。以下示例中父組件Index中@State裝飾的數(shù)組arr激率,將其數(shù)組項(xiàng)初始化子組件Child中@Prop裝飾的value。
@Component
struct Child {
@Prop value: number = 0;
build() {
Text(`${this.value}`)
.fontSize(50)
.onClick(() => {
this.value++
})
}
}
@Entry
@Component
struct Index {
@State arr: number[] = [1, 2, 3];
build() {
Row() {
Column() {
Child({ value: this.arr[0] })
Child({ value: this.arr[1] })
Child({ value: this.arr[2] })
Divider().height(5)
ForEach(this.arr,
(item: number) => {
Child({ value: item })
},
(item: string) => item.toString()
)
Text('replace entire arr')
.fontSize(50)
.onClick(() => {
// 兩個(gè)數(shù)組都包含項(xiàng)“3”勿决。
this.arr = this.arr[0] == 1 ? [3, 4, 5] : [1, 2, 3];
})
}
}
}
}
初始渲染創(chuàng)建6個(gè)子組件實(shí)例乒躺,每個(gè)@Prop裝飾的變量初始化都在本地拷貝了一份數(shù)組項(xiàng)。子組件onclick事件處理程序會(huì)更改局部變量值低缩。
如果點(diǎn)擊界面上的“1”六下嘉冒,“2”五下、“3”四下表制,將所有變量的本地取值都變?yōu)椤?”健爬。
7
7
7
----
7
7
7
單擊replace entire arr后,屏幕將顯示以下信息么介。
3
4
5
----
7
4
5
在子組件Child中做的所有的修改都不會(huì)同步回父組件Index組件,所以即使6個(gè)組件顯示都為7蜕衡,但在父組件Index中壤短,this.arr保存的值依舊是[1,2,3]。
點(diǎn)擊replace entire arr慨仿,this.arr[0] == 1成立久脯,將this.arr賦值為[3, 4, 5];
因?yàn)閠his.arr[0]已更改镰吆,Child({value: this.arr[0]})組件將this.arr[0]更新同步到實(shí)例@Prop裝飾的變量帘撰。Child({value: this.arr[1]})和Child({value: this.arr[2]})的情況也類似。
this.arr的更改觸發(fā)ForEach更新万皿,this.arr更新的前后都有數(shù)值為3的數(shù)組項(xiàng):[3, 4, 5] 和[1, 2, 3]摧找。根據(jù)diff算法,數(shù)組項(xiàng)“3”將被保留牢硅,刪除“1”和“2”的數(shù)組項(xiàng)蹬耘,添加為“4”和“5”的數(shù)組項(xiàng)。這就意味著减余,數(shù)組項(xiàng)“3”的組件不會(huì)重新生成综苔,而是將其移動(dòng)到第一位。所以“3”對(duì)應(yīng)的組件不會(huì)更新,此時(shí)“3”對(duì)應(yīng)的組件數(shù)值為“7”如筛,F(xiàn)orEach最終的渲染結(jié)果是“7”堡牡,“4”,“5”杨刨。
從父組件中的@State類對(duì)象屬性到@Prop簡單類型的同步
如果圖書館有一本圖書和兩位用戶悴侵,每位用戶都可以將圖書標(biāo)記為已讀,此標(biāo)記行為不會(huì)影響其它讀者用戶拭嫁。從代碼角度講可免,對(duì)@Prop圖書對(duì)象的本地更改不會(huì)同步給圖書館組件中的@State圖書對(duì)象。
在此示例中做粤,圖書類可以使用@Observed裝飾器浇借,但不是必須的,只有在嵌套結(jié)構(gòu)時(shí)需要此裝飾器怕品。這一點(diǎn)我們會(huì)在 從父組件中的@State數(shù)組項(xiàng)到@Prop class類型的同步 說明妇垢。
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)
Text(`...has${this.book.pages} pages!`)
Text(`...${this.book.readIt ? "I have read" : 'I have not read it'}`)
.onClick(() => this.book.readIt = true)
}
}
}
@Entry
@Component
struct Library {
@State book: Book = new Book('100 secrets of C++', 765);
build() {
Column() {
ReaderComp({ book: this.book })
ReaderComp({ book: this.book })
}
}
}
從父組件中的@State數(shù)組項(xiàng)到@Prop class類型的同步
在下面的示例中,更改了@State 裝飾的allBooks數(shù)組中Book對(duì)象上的屬性肉康,但點(diǎn)擊“Mark read for everyone”無反應(yīng)闯估。這是因?yàn)樵搶傩允堑诙拥那短讓傩裕珸State裝飾器只能觀察到第一層屬性吼和,不會(huì)觀察到此屬性更改涨薪,所以框架不會(huì)更新ReaderComp。
let nextId: number = 1;
// @Observed
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 : "Book is undefined"}`).fontColor('#e6000000')
Text(` has ${this.book ? this.book.pages : "Book is undefined"} pages!`).fontColor('#e6000000')
Text(` ${this.book ? this.book.readIt ? "I have read" : 'I have not read it' : "Book is undefined"}`).fontColor('#e6000000')
.onClick(() => this.book.readIt = true)
}
}
}
@Entry
@Component
struct Library {
@State allBooks: Book[] = [new Book("C#", 765), new Book("JS", 652), new Book("TS", 765)];
build() {
Column() {
Text('library`s all time favorite')
.width(312)
.height(40)
.backgroundColor('#0d000000')
.borderRadius(20)
.margin(12)
.padding({ left: 20 })
.fontColor('#e6000000')
ReaderComp({ book: this.allBooks[2] })
.backgroundColor('#0d000000')
.width(312)
.height(40)
.padding({ left: 20, top: 10 })
.borderRadius(20)
.colorBlend('#e6000000')
Divider()
Text('Books on loaan to a reader')
.width(312)
.height(40)
.backgroundColor('#0d000000')
.borderRadius(20)
.margin(12)
.padding({ left: 20 })
.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('Add new')
.width(312)
.height(40)
.margin(12)
.fontColor('#FFFFFF 90%')
.onClick(() => {
this.allBooks.push(new Book("JA", 512));
})
Button('Remove first book')
.width(312)
.height(40)
.margin(12)
.fontColor('#FFFFFF 90%')
.onClick(() => {
if (this.allBooks.length > 0){
this.allBooks.shift();
} else {
console.log("length <= 0")
}
})
Button("Mark read for everyone")
.width(312)
.height(40)
.margin(12)
.fontColor('#FFFFFF 90%')
.onClick(() => {
this.allBooks.forEach((book) => book.readIt = true)
})
}
}
}
需要使用@Observed裝飾class Book炫乓,Book的屬性將被觀察刚夺。 需要注意的是,@Prop在子組件裝飾的狀態(tài)變量和父組件的數(shù)據(jù)源是單向同步關(guān)系末捣,即ReaderComp中的@Prop book的修改不會(huì)同步給父組件Library侠姑。而父組件只會(huì)在數(shù)值有更新的時(shí)候(和上一次狀態(tài)的對(duì)比),才會(huì)觸發(fā)UI的重新渲染箩做。
@Observed
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;
}
}
@Observed裝飾的類的實(shí)例會(huì)被不透明的代理對(duì)象包裝莽红,此代理可以檢測到包裝對(duì)象內(nèi)的所有屬性更改。如果發(fā)生這種情況邦邦,此時(shí)安吁,代理通知@Prop,@Prop對(duì)象值被更新圃酵。
@Prop本地初始化不和父組件同步
為了支持@Component裝飾的組件復(fù)用場景柳畔,@Prop支持本地初始化,這樣可以讓@Prop是否與父組件建立同步關(guān)系變得可選郭赐。當(dāng)且僅當(dāng)@Prop有本地初始化時(shí)薪韩,從父組件向子組件傳遞@Prop的數(shù)據(jù)源才是可選的确沸。
下面的示例中,子組件包含兩個(gè)@Prop變量:
@Prop customCounter沒有本地初始化俘陷,所以需要父組件提供數(shù)據(jù)源去初始化@Prop罗捎,并當(dāng)父組件的數(shù)據(jù)源變化時(shí),@Prop也將被更新拉盾;
@Prop customCounter2有本地初始化桨菜,在這種情況下,@Prop依舊允許但非強(qiáng)制父組件同步數(shù)據(jù)源給@Prop捉偏。
@Component
struct MyComponent {
@Prop customCounter: number;
@Prop customCounter2: number = 5;
build() {
Column() {
Row() {
Text(`From Main: ${this.customCounter}`).fontColor('#ff6b6565').margin({ left: -110, top: 12 })
}
Row() {
Button('Click to change locally !')
.width(288)
.height(40)
.margin({ left: 30, top: 12 })
.fontColor('#FFFFFF倒得,90%')
.onClick(() => {
this.customCounter2++
})
}
Row() {
Text(`Custom Local: ${this.customCounter2}`).fontColor('#ff6b6565').margin({ left: -110, top: 12 })
}
}
}
}
@Entry
@Component
struct MainProgram {
@State mainCounter: number = 10;
build() {
Column() {
Row() {
Column() {
// customCounter必須從父組件初始化,因?yàn)镸yComponent的customCounter成員變量缺少本地初始化夭禽;此處霞掺,customCounter2可以不做初始化。
MyComponent({ customCounter: this.mainCounter })
// customCounter2也可以從父組件初始化讹躯,父組件初始化的值會(huì)覆蓋子組件customCounter2的本地初始化的值
MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
}
}
Row() {
Column() {
Button('Click to change number')
.width(288)
.height(40)
.margin({ left: 30, top: 12 })
.fontColor('#FFFFFF菩彬,90%')
.onClick(() => {
this.mainCounter++
})
}
}
}
}
}
@Prop嵌套場景
在嵌套場景下,每一層都要用@Observed裝飾潮梯,且每一層都要被@Prop接收骗灶,這樣才能觀察到嵌套場景。
// 以下是嵌套類對(duì)象的數(shù)據(jù)結(jié)構(gòu)秉馏。
@Observed
class ClassA {
public title: string;
constructor(title: string) {
this.title = title;
}
}
@Observed
class ClassB {
public name: string;
public a: ClassA;
constructor(name: string, a: ClassA) {
this.name = name;
this.a = a;
}
}
以下組件層次結(jié)構(gòu)呈現(xiàn)的是@Prop嵌套場景的數(shù)據(jù)結(jié)構(gòu)耙旦。
@Entry
@Component
struct Parent {
@State votes: ClassB = new ClassB('Hello', new ClassA('world'))
build() {
Column() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
Button('change ClassB name')
.width(312)
.height(40)
.margin(12)
.fontColor('#FFFFFF,90%')
.onClick(() => {
this.votes.name = "aaaaa"
})
Button('change ClassA title')
.width(312)
.height(40)
.margin(12)
.fontColor('#FFFFFF沃饶,90%')
.onClick(() => {
this.votes.a.title = "wwwww"
})
Text(this.votes.name)
.fontSize(16)
.margin(12)
.width(312)
.height(40)
.backgroundColor('#ededed')
.borderRadius(20)
.textAlign(TextAlign.Center)
.fontColor('#e6000000')
.onClick(() => {
this.votes.name = 'Bye'
})
Text(this.votes.a.title)
.fontSize(16)
.margin(12)
.width(312)
.height(40)
.backgroundColor('#ededed')
.borderRadius(20)
.textAlign(TextAlign.Center)
.onClick(() => {
this.votes.a.title = "openHarmony"
})
Child1({ vote1: this.votes.a })
}
}
}
}
@Component
struct Child1 {
@Prop vote1: ClassA = new ClassA('');
build() {
Column() {
Text(this.vote1.title)
.fontSize(16)
.margin(12)
.width(312)
.height(40)
.backgroundColor('#ededed')
.borderRadius(20)
.textAlign(TextAlign.Center)
.onClick(() => {
this.vote1.title = 'Bye Bye'
})
}
}
}
裝飾Map類型變量
說明:
從API version 11開始母廷,@Prop支持Map類型。
在下面的示例中糊肤,value類型為Map<number, string>,點(diǎn)擊Button改變message的值氓鄙,視圖會(huì)隨之刷新馆揉。
@Component
struct Child {
@Prop value: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])
build() {
Column() {
ForEach(Array.from(this.value.entries()), (item: [number, string]) => {
Text(`${item[0]}`).fontSize(30)
Text(`${item[1]}`).fontSize(30)
Divider()
})
Button('child init map').onClick(() => {
this.value = new Map([[0, "a"], [1, "b"], [3, "c"]])
})
Button('child set new one').onClick(() => {
this.value.set(4, "d")
})
Button('child clear').onClick(() => {
this.value.clear()
})
Button('child replace the first one').onClick(() => {
this.value.set(0, "aa")
})
Button('child delete the first one').onClick(() => {
this.value.delete(0)
})
}
}
}
@Entry
@Component
struct MapSample2 {
@State message: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])
build() {
Row() {
Column() {
Child({ value: this.message })
}
.width('100%')
}
.height('100%')
}
}
裝飾Set類型變量
說明:
從API version 11開始,@Prop支持Set類型抖拦。
在下面的示例中升酣,message類型為Set<number>,點(diǎn)擊Button改變message的值态罪,視圖會(huì)隨之刷新噩茄。
@Component
struct Child {
@Prop message: Set<number> = new Set([0, 1, 2, 3, 4])
build() {
Column() {
ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
Text(`${item[0]}`).fontSize(30)
Divider()
})
Button('init set').onClick(() => {
this.message = new Set([0, 1, 2, 3, 4])
})
Button('set new one').onClick(() => {
this.message.add(5)
})
Button('clear').onClick(() => {
this.message.clear()
})
Button('delete the first one').onClick(() => {
this.message.delete(0)
})
}
.width('100%')
}
}
@Entry
@Component
struct SetSample11 {
@State message: Set<number> = new Set([0, 1, 2, 3, 4])
build() {
Row() {
Column() {
Child({ message: this.message })
}
.width('100%')
}
.height('100%')
}
}
Prop支持聯(lián)合類型實(shí)例
@Prop支持聯(lián)合類型和undefined和null,在下面的示例中复颈,animal類型為Animals | undefined绩聘,點(diǎn)擊父組件Zoo中的Button改變animal的屬性或者類型,Child中也會(huì)對(duì)應(yīng)刷新。
class Animals {
public name: string;
constructor(name: string) {
this.name = name;
}
}
@Component
struct Child {
@Prop animal: Animals | undefined;
build() {
Column() {
Text(`Child's animal is ${this.animal instanceof Animals ? this.animal.name : 'undefined'}`).fontSize(30)
Button('Child change animals into tigers')
.onClick(() => {
// 賦值為Animals的實(shí)例
this.animal = new Animals("Tiger")
})
Button('Child change animal to undefined')
.onClick(() => {
// 賦值為undefined
this.animal = undefined
})
}.width('100%')
}
}
@Entry
@Component
struct Zoo {
@State animal: Animals | undefined = new Animals("lion");
build() {
Column() {
Text(`Parents' animals are ${this.animal instanceof Animals ? this.animal.name : 'undefined'}`).fontSize(30)
Child({animal: this.animal})
Button('Parents change animals into dogs')
.onClick(() => {
// 判斷animal的類型凿菩,做屬性的更新
if (this.animal instanceof Animals) {
this.animal.name = "Dog"
} else {
console.info('num is undefined, cannot change property')
}
})
Button('Parents change animal to undefined')
.onClick(() => {
// 賦值為undefined
this.animal = undefined
})
}
}
}
常見問題
@Prop裝飾狀態(tài)變量未初始化錯(cuò)誤
@Prop需要被初始化机杜,如果沒有進(jìn)行本地初始化的,則必須通過父組件進(jìn)行初始化衅谷。如果進(jìn)行了本地初始化椒拗,那么是可以不通過父組件進(jìn)行初始化的。
【反例】
@Observed
class Commodity {
public price: number = 0;
constructor(price: number) {
this.price = price;
}
}
@Component
struct PropChild {
@Prop fruit: Commodity; // 未進(jìn)行本地初始化
build() {
Text(`PropChild fruit ${this.fruit.price}`)
.onClick(() => {
this.fruit.price += 1;
})
}
}
@Entry
@Component
struct Parent {
@State fruit: Commodity[] = [new Commodity(1)];
build() {
Column() {
Text(`Parent fruit ${this.fruit[0].price}`)
.onClick(() => {
this.fruit[0].price += 1;
})
// @Prop本地沒有初始化获黔,也沒有從父組件初始化
PropChild()
}
}
}
【正例】
@Observed
class Commodity {
public price: number = 0;
constructor(price: number) {
this.price = price;
}
}
@Component
struct PropChild1 {
@Prop fruit: Commodity; // 未進(jìn)行本地初始化
build() {
Text(`PropChild1 fruit ${this.fruit.price}`)
.onClick(() => {
this.fruit.price += 1;
})
}
}
@Component
struct PropChild2 {
@Prop fruit: Commodity = new Commodity(1); // 進(jìn)行本地初始化
build() {
Text(`PropChild2 fruit ${this.fruit.price}`)
.onClick(() => {
this.fruit.price += 1;
})
}
}
@Entry
@Component
struct Parent {
@State fruit: Commodity[] = [new Commodity(1)];
build() {
Column() {
Text(`Parent fruit ${this.fruit[0].price}`)
.onClick(() => {
this.fruit[0].price += 1;
})
// @PropChild1本地沒有初始化蚀苛,必須從父組件初始化
PropChild1({ fruit: this.fruit[0] })
// @PropChild2本地進(jìn)行了初始化,可以不從父組件初始化玷氏,也可以從父組件初始化
PropChild2()
PropChild2({ fruit: this.fruit[0] })
}
}
}
寫在最后
- 如果你覺得這篇內(nèi)容對(duì)你還蠻有幫助堵未,我想邀請(qǐng)你幫我三個(gè)小忙:
- 點(diǎn)贊,轉(zhuǎn)發(fā)预茄,有你們的 『點(diǎn)贊和評(píng)論』兴溜,才是我創(chuàng)造的動(dòng)力。
- 關(guān)注小編耻陕,同時(shí)可以期待后續(xù)文章ing??拙徽,不定期分享原創(chuàng)知識(shí)。
- 想要獲取更多完整鴻蒙最新學(xué)習(xí)知識(shí)點(diǎn)诗宣,請(qǐng)移步前往小編:
https://gitee.com/MNxiaona/733GH/blob/master/jianshu