W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
上文所述的裝飾器僅能觀察到第一層的變化,但是在實際應用開發(fā)中,應用會根據(jù)開發(fā)需要,封裝自己的數(shù)據(jù)模型。對于多層嵌套的情況,比如二維數(shù)組,或者數(shù)組項class,或者class的屬性是class,他們的第二層的屬性變化是無法觀察到的。這就引出了@Observed/@ObjectLink裝飾器。
從API version 9開始,這兩個裝飾器支持在ArkTS卡片中使用。
@ObjectLink和@Observed類裝飾器用于在涉及嵌套對象或數(shù)組的場景中進行雙向數(shù)據(jù)同步:
@Observed類裝飾器 | 說明 |
---|---|
裝飾器參數(shù) | 無 |
類裝飾器 | 裝飾class。需要放在class的定義前,使用new創(chuàng)建類對象。 |
@ObjectLink變量裝飾器 | 說明 |
---|---|
裝飾器參數(shù) | 無 |
同步類型 | 不與父組件中的任何類型同步變量。 |
允許裝飾的變量類型 | 必須為被@Observed裝飾的class實例,必須指定類型。 不支持簡單類型,可以使用@Prop。 @ObjectLink的屬性是可以改變的,但是變量的分配是不允許的,也就是說這個裝飾器裝飾變量是只讀的,不能被改變。 |
被裝飾變量的初始值 | 不允許。 |
@ObjectLink裝飾的數(shù)據(jù)為可讀示例。
- // 允許@ObjectLink裝飾的數(shù)據(jù)屬性賦值
- this.objLink.a= ...
- // 不允許@ObjectLink裝飾的數(shù)據(jù)自身賦值
- this.objLink= ...
@ObjectLink裝飾的變量不能被賦值,如果要使用賦值操作,請使用@Prop。
@ObjectLink傳遞/訪問 | 說明 |
---|---|
從父組件初始化 | 必須指定。 初始化@ObjectLink裝飾的變量必須同時滿足以下場景:
|
與源對象同步 | 雙向。 |
可以初始化子組件 | 允許,可用于初始化常規(guī)變量、@State、@Link、@Prop、@Provide |
@Observed裝飾的類,如果其屬性為非簡單類型,比如class、Object或者數(shù)組,也需要被@Observed裝飾,否則將觀察不到其屬性的變化。
- class ClassA {
- public c: number;
- constructor(c: number) {
- this.c = c;
- }
- }
- @Observed
- class ClassB {
- public a: ClassA;
- public b: number;
- constructor(a: ClassA, b: number) {
- this.a = a;
- this.b = b;
- }
- }
以上示例中,ClassB被@Observed裝飾,其成員變量的賦值的變化是可以被觀察到的,但對于ClassA,沒有被@Observed裝飾,其屬性的修改不能被觀察到。
- @ObjectLink b: ClassB
- // 賦值變化可以被觀察到
- this.b.a = new ClassA(5)
- this.b.b = 5
- // ClassA沒有被@Observed裝飾,其屬性的變化觀察不到
- this.b.a.c = 5
@ObjectLink:@ObjectLink只能接收被@Observed裝飾class的實例,可以觀察到:
以下是嵌套類對象的數(shù)據(jù)結構。
- // objectLinkNestedObjects.ets
- let NextID: number = 1;
- @Observed
- class ClassA {
- public id: number;
- public c: number;
- constructor(c: number) {
- this.id = NextID++;
- this.c = c;
- }
- }
- @Observed
- class ClassB {
- public a: ClassA;
- constructor(a: ClassA) {
- this.a = a;
- }
- }
- @Component
- struct ViewA {
- label: string = 'ViewA1';
- @ObjectLink a: ClassA;
- build() {
- Row() {
- Button(`ViewA [${this.label}] this.a.c=${this.a.c} +1`)
- .onClick(() => {
- this.a.c += 1;
- })
- }
- }
- }
- @Entry
- @Component
- struct ViewB {
- @State b: ClassB = new ClassB(new ClassA(0));
- build() {
- Column() {
- // in low version,DevEco may throw a warning,but it does not matter.
- // you can still compile and run.
- ViewA({ label: 'ViewA #1', a: this.b.a })
- ViewA({ label: 'ViewA #2', a: this.b.a })
- Button(`ViewB: this.b.a.c+= 1`)
- .onClick(() => {
- this.b.a.c += 1;
- })
- Button(`ViewB: this.b.a = new ClassA(0)`)
- .onClick(() => {
- this.b.a = new ClassA(0);
- })
- Button(`ViewB: this.b = new ClassB(ClassA(0))`)
- .onClick(() => {
- this.b = new ClassB(new ClassA(0));
- })
- }
- }
- }
ViewB中的事件句柄:
ViewA中的事件句柄:
對象數(shù)組是一種常用的數(shù)據(jù)結構。以下示例展示了數(shù)組對象的用法。
- @Component
- struct ViewA {
- // 子組件ViewA的@ObjectLink的類型是ClassA
- @ObjectLink a: ClassA;
- label: string = 'ViewA1';
- build() {
- Row() {
- Button(`ViewA [${this.label}] this.a.c = ${this.a.c} +1`)
- .onClick(() => {
- this.a.c += 1;
- })
- }
- }
- }
- @Entry
- @Component
- struct ViewB {
- // ViewB中有@State裝飾的ClassA[]
- @State arrA: ClassA[] = [new ClassA(0), new ClassA(0)];
- build() {
- Column() {
- ForEach(this.arrA,
- (item) => {
- ViewA({ label: `#${item.id}`, a: item })
- },
- (item) => item.id.toString()
- )
- // 使用@State裝飾的數(shù)組的數(shù)組項初始化@ObjectLink,其中數(shù)組項是被@Observed裝飾的ClassA的實例
- ViewA({ label: `ViewA this.arrA[first]`, a: this.arrA[0] })
- ViewA({ label: `ViewA this.arrA[last]`, a: this.arrA[this.arrA.length-1] })
- Button(`ViewB: reset array`)
- .onClick(() => {
- this.arrA = [new ClassA(0), new ClassA(0)];
- })
- Button(`ViewB: push`)
- .onClick(() => {
- this.arrA.push(new ClassA(0))
- })
- Button(`ViewB: shift`)
- .onClick(() => {
- this.arrA.shift()
- })
- Button(`ViewB: chg item property in middle`)
- .onClick(() => {
- this.arrA[Math.floor(this.arrA.length / 2)].c = 10;
- })
- Button(`ViewB: chg item property in middle`)
- .onClick(() => {
- this.arrA[Math.floor(this.arrA.length / 2)] = new ClassA(11);
- })
- }
- }
- }
使用@Observed觀察二維數(shù)組的變化??梢月暶饕粋€被@Observed裝飾的繼承Array的子類。
- @Observed
- class StringArray extends Array<String> {
- }
使用new StringArray()來構造StringArray的實例,new運算符使得@Observed生效,@Observed觀察到StringArray的屬性變化。
聲明一個從Array擴展的類class StringArray extends Array<String> {},并創(chuàng)建StringArray的實例。@Observed裝飾的類需要使用new運算符來構建class實例。
- @Observed
- class StringArray extends Array<String> {
- }
- @Component
- struct ItemPage {
- @ObjectLink itemArr: StringArray;
- build() {
- Row() {
- Text('ItemPage')
- .width(100).height(100)
- ForEach(this.itemArr,
- item => {
- Text(item)
- .width(100).height(100)
- },
- item => item
- )
- }
- }
- }
- @Entry
- @Component
- struct IndexPage {
- @State arr: Array<StringArray> = [new StringArray(), new StringArray(), new StringArray()];
- build() {
- Column() {
- ItemPage({ itemArr: this.arr[0] })
- ItemPage({ itemArr: this.arr[1] })
- ItemPage({ itemArr: this.arr[2] })
- Divider()
- ForEach(this.arr,
- itemArr => {
- ItemPage({ itemArr: itemArr })
- },
- itemArr => itemArr[0]
- )
- Divider()
- Button('update')
- .onClick(() => {
- console.error('Update all items in arr');
- if (this.arr[0][0] !== undefined) {
- // 正常情況下需要有一個真實的ID來與ForEach一起使用,但此處沒有
- // 因此需要確保推送的字符串是唯一的。
- this.arr[0].push(`${this.arr[0].slice(-1).pop()}${this.arr[0].slice(-1).pop()}`);
- this.arr[1].push(`${this.arr[1].slice(-1).pop()}${this.arr[1].slice(-1).pop()}`);
- this.arr[2].push(`${this.arr[2].slice(-1).pop()}${this.arr[2].slice(-1).pop()}`);
- } else {
- this.arr[0].push('Hello');
- this.arr[1].push('World');
- this.arr[2].push('!');
- }
- })
- }
- }
- }
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: