衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Harmony 鴻蒙頁面級變量的狀態管理

王程 ? 來源:jf_75796907 ? 作者:jf_75796907 ? 2024-01-25 10:42 ? 次閱讀

頁面級變量的狀態管理

@State、@Prop、@Link、@Provide、@Consume、@ObjectLink、@Observed和@Watch用于管理頁面級變量的狀態。

@State

@State裝飾的變量是組件內部的狀態數據,當這些狀態數據被修改時,將會調用所在組件的build方法進行UI刷新。
@State狀態數據具有以下特征:

  • 支持多種類型數據:支持class、number、boolean、string強類型數據的值類型和引用類型,以及這些強類型構成的數組,即Array、Array、Array、Array。不支持object和any。
  • 支持多實例:組件不同實例的內部狀態數據獨立。
  • 內部私有:標記為@State的屬性是私有變量,只能在組件內訪問。
  • 需要本地初始化:必須為所有@State變量分配初始值,變量未初始化可能導致未定義的框架異常行為。
  • 創建自定義組件時支持通過狀態變量名設置初始值:在創建組件實例時,可以通過變量名顯式指定@State狀態變量的初始值。

示例:

在下面的示例中:

  • 用戶定義的組件MyComponent定義了@State狀態變量count和title。如果count或title的值發生變化,則執行MyComponent的build方法來重新渲染組件;
  • EntryComponent中有多個MyComponent組件實例,第一個MyComponent內部狀態的更改不會影響第二個MyComponent;
  • 創建MyComponent實例時通過變量名給組件內的變量進行初始化,如:
MyComponent({ title: { value: 'Hello World 2' }, count: 7 })
// xxx.ets
class Model {
  value: string

  constructor(value: string) {
    this.value = value
  }
}

@Entry
@Component
struct EntryComponent {
  build() {
    Column() {
      MyComponent({ count: 1, increaseBy: 2 }) // 第1個MyComponent實例
      MyComponent({ title: { value: 'Hello World 2' }, count: 7 }) // 第2個MyComponent實例
    }
  }
}

@Component
struct MyComponent {
  @State title: Model = { value: 'Hello World' }
  @State count: number = 0
  private toggle: string = 'Hello World'
  private increaseBy: number = 1

  build() {
    Column() {
      Text(`${this.title.value}`).fontSize(30)
      Button('Click to change title')
        .margin(20)
        .onClick(() = > {
          // 修改內部狀態變量title
          this.title.value = (this.toggle == this.title.value) ? 'Hello World' : 'Hello ArkUI'
        })

      Button(`Click to increase count=${this.count}`)
        .margin(20)
        .onClick(() = > {
          // 修改內部狀態變量count
          this.count += this.increaseBy
        })
    }
  }

@Prop

@Prop與@State有相同的語義,但初始化方式不同。@Prop裝飾的變量必須使用其父組件提供的@State變量進行初始化,允許組件內部修改@Prop變量,但變量的更改不會通知給父組件,父組件變量的更改會同步到@prop裝飾的變量,即@Prop屬于單向數據綁定。
@Prop狀態數據具有以下特征:

  • 支持簡單類型:僅支持number、string、boolean等簡單數據類型;
  • 私有:僅支持組件內訪問;
  • 支持多個實例:一個組件中可以定義多個標有@Prop的屬性;
  • 創建自定義組件時將值傳遞給@Prop變量進行初始化:在創建組件的新實例時,必須初始化所有@Prop變量,不支持在組件內部進行初始化。

說明:
@Prop修飾的變量不能在組件內部進行初始化。

示例:

在下面的示例中,當按“+1”或“-1”按鈕時,父組件狀態發生變化,重新執行build方法,此時將創建一個新的CountDownComponent組件實例。父組件的countDownStartValue狀態變量被用于初始化子組件的@Prop變量,當按下子組件的“count - costOfOneAttempt”按鈕時,其@Prop變量count將被更改,CountDownComponent重新渲染,但是count值的更改不會影響父組件的countDownStartValue值。

// xxx.ets
@Entry
@Component
struct ParentComponent {
  @State countDownStartValue: number = 10 // 初始化countDownStartValue

  build() {
    Column() {
      Text(`Grant ${this.countDownStartValue} nuggets to play.`).fontSize(18)
      Button('+1 - Nuggets in New Game')
        .margin(15)
        .onClick(() = > {
          this.countDownStartValue += 1
        })

      Button('-1  - Nuggets in New Game')
        .margin(15)
        .onClick(() = > {
          this.countDownStartValue -= 1
        })
      // 創建子組件時,必須在構造函數參數中提供其@Prop變量count的初始值,同時初始化常規變量costOfOneAttempt(非Prop變量)
      CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
    }
  }
}

@Component
struct CountDownComponent {
  @Prop count: number
  private costOfOneAttempt: number

  build() {
    Column() {
      if (this.count > 0) {
        Text(`You have ${this.count} Nuggets left`).fontSize(18)
      } else {
        Text('Game over!').fontSize(18)
      }

      Button('count - costOfOneAttempt')
        .margin(15)
        .onClick(() = > {
          this.count -= this.costOfOneAttempt
        })
    }
  }
}

@Link

@Link裝飾的變量可以和父組件的@State變量建立雙向數據綁定:

  • 支持多種類型:@Link支持的數據類型與@State相同,即class、number、string、boolean或這些類型的數組;
  • 私有:僅支持組件內訪問;
  • 單個數據源:父組件中用于初始化子組件@Link變量的必須是父組件定義的狀態變量;
  • 雙向通信:子組件對@Link變量的更改將同步修改父組件中的@State變量;
  • 創建自定義組件時需要將變量的引用傳遞給@Link變量,在創建組件的新實例時,必須使用命名參數初始化所有@Link變量。@Link變量可以使用@State變量或@Link變量的引用進行初始化,@State變量可以通過'$'操作符創建引用。

說明:
@Link修飾的變量不能在組件內部進行初始化。

簡單類型示例:

@Link語義是從''操作符引出,即isPlaying是this.isPlaying內部狀態的雙向數據綁定。當單擊子組件PlayButton中的按鈕時,@Link變量更改,PlayButton與父組件中的Text和Button將同時進行刷新,同樣地,當點擊父組件中的Button修改this.isPlaying時,子組件PlayButton與父組件中的Text和Button也將同時刷新。

// xxx.ets
@Entry
@Component
struct Player {
  @State isPlaying: boolean = false

  build() {
    Column() {
      PlayButton({ buttonPlaying: $isPlaying })
      Text(`Player is ${this.isPlaying ? '' : 'not'} playing`).fontSize(18)
      Button('Parent:' + this.isPlaying)
        .margin(15)
        .onClick(() = > {
          this.isPlaying = !this.isPlaying
        })
    }
  }
}

@Component
struct PlayButton {
  @Link buttonPlaying: boolean

  build() {
    Column() {
      Button(this.buttonPlaying ? 'pause' : 'play')
        .margin(20)
        .onClick(() = > {
          this.buttonPlaying = !this.buttonPlaying
        })
    }
  }
}

復雜類型示例:

// xxx.ets
@Entry
@Component
struct Parent {
  @State arr: number[] = [1, 2, 3]

  build() {
    Column() {
      Child({ items: $arr })
      Button('Parent Button: splice')
        .margin(10)
        .onClick(() = > {
          this.arr.splice(0, 1, 60)
        })
      ForEach(this.arr, item = > {
        Text(item.toString()).fontSize(18).margin(10)
      }, item = > item.toString())
    }
  }
}


@Component
struct Child {
  @Link items: number[]

  build() {
    Column() {
      Button('Child Button1: push')
        .margin(15)
        .onClick(() = > {
          this.items.push(100)
        })
      Button('Child Button2: replace whole item')
        .margin(15)
        .onClick(() = > {
          this.items = [100, 200, 300]
        })
    }
  }
}

@Link、@State和@Prop結合使用示例:
下面示例中,ParentView包含ChildA和ChildB兩個子組件,ParentView的狀態變量counter分別用于初始化ChildA的@Prop變量和ChildB的@Link變量。

  • ChildB使用@Link建立雙向數據綁定,當ChildB修改counterRef狀態變量值時,該更改將同步到ParentView和ChildA共享;
  • ChildA使用@Prop建立從ParentView到自身的單向數據綁定,當ChildA修改counterVal狀態變量值時,ChildA將重新渲染,但該更改不會傳達給ParentView和ChildB。
// xxx.ets
@Entry
@Component
struct ParentView {
  @State counter: number = 0

  build() {
    Column() {
      ChildA({ counterVal: this.counter })
      ChildB({ counterRef: $counter })
    }
  }
}

@Component
struct ChildA {
  @Prop counterVal: number

  build() {
    Button(`ChildA: (${this.counterVal}) + 1`)
      .margin(15)
      .onClick(() = > {
        this.counterVal += 1
      })
  }
}

@Component
struct ChildB {
  @Link counterRef: number

  build() {
    Button(`ChildB: (${this.counterRef}) + 1`)
      .margin(15)
      .onClick(() = > {
        this.counterRef += 1
      })
  }
}

@Observed和ObjectLink數據管理

開發者需要在子組件中針對父組件的一個變量(parent_a)設置雙向同步時,開發者可以在父組件中使用@State裝飾變量(parent_a),并在子組件中使用@Link裝飾對應的變量(child_a)。這樣不僅可以實現父組件與單個子組件之間的數據同步,也可以實現父組件與多個子組件之間的數據同步。如下圖所示,可以看到,父子組件針對ClassA類型的變量設置了雙向同步,那么當子組件1中變量對應的屬性c的值變化時,會通知父組件同步變化,而當父組件中屬性c的值變化時,會通知所有子組件同步變化。

然而,上述例子是針對某個數據對象進行的整體同步,而當開發者只想針對父組件中某個數據對象的部分信息進行同步時,使用@Link就不能滿足要求。如果這些部分信息是一個類對象,就可以使用@ObjectLink配合@Observed來實現,如下圖所示。

設置要求

@Observed用于類,@ObjectLink用于變量。

@ObjectLink裝飾的變量類型必須為類(class type)。

  • 類要被@Observed裝飾器所裝飾。
  • 不支持簡單類型參數,可以使用@Prop進行單向同步。

@ObjectLink裝飾的變量是不可變的。

  • 屬性的改動是被允許的,當改動發生時,如果同一個對象被多個@ObjectLink變量所引用,那么所有擁有這些變量的自定義組件都會被通知進行重新渲染。

@ObjectLink裝飾的變量不可設置默認值。

  • 必須讓父組件中有一個由@State、@Link、@StorageLink、@Provide或@Consume裝飾的變量所參與的TS表達式進行初始化。

@ObjectLink裝飾的變量是私有變量,只能在組件內訪問。

示例

// xxx.ets
// 父組件ViewB中的類對象ClassA與子組件ViewA保持數據同步時,可以使用@ObjectLink和@Observed,綁定該數據對象的父組件和其他子組件同步更新
var nextID: number = 0

@Observed
class ClassA {
  public name: string
  public c: number
  public id: number

  constructor(c: number, name: string = 'OK') {
    this.name = name
    this.c = c
    this.id = nextID++
  }
}

@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
        })
    }.margin({ top: 10 })
  }
}

@Entry
@Component
struct ViewB {
  @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())
      ViewA({ label: `this.arrA[first]`, a: this.arrA[0] })
      ViewA({ label: `this.arrA[last]`, a: this.arrA[this.arrA.length - 1] })

      Button(`ViewB: reset array`)
        .margin({ top: 10 })
        .onClick(() = > {
          this.arrA = [new ClassA(0), new ClassA(0)]
        })
      Button(`ViewB: push`)
        .margin({ top: 10 })
        .onClick(() = > {
          this.arrA.push(new ClassA(0))
        })
      Button(`ViewB: shift`)
        .margin({ top: 10 })
        .onClick(() = > {
          this.arrA.shift()
        })
    }.width('100%')
  }
}

@Provide和@Consume

@Provide作為數據的提供方,可以更新其子孫節點的數據,并觸發頁面渲染。@Consume在感知到@Provide數據的更新后,會觸發當前自定義組件的重新渲染。

說明:
使用@Provide和@Consume時應避免循環引用導致死循環。

@Provide

名稱說明
裝飾器參數是一個string類型的常量,用于給裝飾的變量起別名。如果規定別名,則提供對應別名的數據更新。如果沒有,則使用變量名作為別名。推薦使用@Provide(‘alias’)這種形式。
同步機制@Provide的變量類似@State,可以修改對應變量進行頁面重新渲染。也可以修改@Consume裝飾的變量,反向修改@State變量。
初始值必須設置初始值。
頁面重渲染場景基礎類型(boolean,string,number)變量的改變;@Observed class類型變量及其屬性的修改;添加,刪除,更新數組中的元素。

@Consume

類型說明
初始值不可設置默認初始值。

示例

// xxx.ets
@Entry
@Component
struct CompA {
  @Provide("reviewVote") reviewVotes: number = 0;

  build() {
    Column() {
      CompB()
      Button(`CompA: ${this.reviewVotes}`)
        .margin(10)
        .onClick(() = > {
          this.reviewVotes += 1;
        })
    }
  }
}

@Component
struct CompB {
  build() {
    Column() {
      CompC()
    }
  }
}

@Component
struct CompC {
  @Consume("reviewVote") reviewVotes: number

  build() {
    Column() {
      Button(`CompC: ${this.reviewVotes}`)
        .margin(10)
        .onClick(() = > {
          this.reviewVotes += 1
        })
    }.width('100%')
  }
}

@Watch

@Watch用于監聽狀態變量的變化,語法結構為:

@State @Watch("onChanged") count : number = 0

如上所示,給狀態變量增加一個@Watch裝飾器,通過@Watch注冊一個回調方法onChanged, 當狀態變量count被改變時, 觸發onChanged回調。

裝飾器@State、@Prop、@Link、@ObjectLink、@Provide、@Consume、@StorageProp以及@StorageLink所裝飾的變量均可以通過@Watch監聽其變化。

說明:
深層次數據修改不會觸發@Watch回調,例如無法監聽數組中對象值的改變。

// xxx.ets
@Entry
@Component
struct CompA {
  @State @Watch('onBasketUpdated') shopBasket: Array< number > = [7, 12, 47, 3]
  @State totalPurchase: number = 0
  @State addPurchase: number = 0

  aboutToAppear() {
    this.updateTotal()
  }

  updateTotal(): void {
    let sum = 0;
    this.shopBasket.forEach((i) = > {
      sum += i
    })
    // 計算新的購物籃總價值,如果超過100,則適用折扣
    this.totalPurchase = (sum < 100) ? sum : 0.9 * sum
    return this.totalPurchase
  }

  // shopBasket更改時觸發該方法
  onBasketUpdated(propName: string): void {
    this.updateTotal()
  }

  build() {
    Column() {
      Button('add to basket ' + this.addPurchase)
        .margin(15)
        .onClick(() = > {
          this.addPurchase = Math.round(100 * Math.random())
          this.shopBasket.push(this.addPurchase)
        })
      Text(`${this.totalPurchase}`)
        .fontSize(30)
    }
  }
}

審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 變量
    +關注

    關注

    0

    文章

    613

    瀏覽量

    28463
  • 鴻蒙
    +關注

    關注

    57

    文章

    2392

    瀏覽量

    43050
  • Harmony
    +關注

    關注

    0

    文章

    54

    瀏覽量

    2640
收藏 人收藏

    評論

    相關推薦

    OpenHarmony頁面變量狀態管理

    @State、@Prop、@Link、@Provide、Consume、@ObjectLink、@Observed和@Watch用于管理頁面變量
    的頭像 發表于 12-07 08:58 ?2774次閱讀

    鴻蒙開發教程-管理組件狀態

    跨組件層級雙向同步狀態是指@Provide修飾的狀態變量自動對提供者組件的所有后代組件可用,后代組件通過使用@Consume裝飾的變量來獲得對提供的狀態變量的訪問。
    的頭像 發表于 01-22 21:46 ?1405次閱讀
    <b class='flag-5'>鴻蒙</b>開發教程-<b class='flag-5'>管理</b>組件<b class='flag-5'>狀態</b>

    鴻蒙OS開發實例:【應用狀態變量共享】

    平時在開發的過程中,我們會在應用中共享數據,在不同的頁面間共享信息。雖然常用的共享信息,也可以通過不同頁面中組件間信息共享的方式,但有時使用應用級別的狀態管理會讓開發工作變得簡單。
    的頭像 發表于 04-03 15:09 ?1448次閱讀
    <b class='flag-5'>鴻蒙</b>OS開發實例:【應用<b class='flag-5'>狀態變量</b>共享】

    harmonyos開發者平臺

    使用@State、@Prop、@Link、@Watch、@Provide、@Consume管理頁面變量狀態,實現對
    的頭像 發表于 05-06 16:02 ?907次閱讀
    harmonyos開發者平臺

    HarmonyOS實踐之應用狀態變量共享

    平時在開發的過程中,我們會在應用中共享數據,在不同的頁面間共享信息。雖然常用的共享信息,也可以通過不同頁面中組件間信息共享的方式,但有時使用應用級別的狀態管理會讓開發工作變得簡單。 根
    發表于 12-27 09:48

    Harmony 鴻蒙頁面變量狀態管理

    頁面變量狀態管理 @State、@Prop、@Link、@Provide、@Consume、@ObjectLink、@Observed和
    發表于 01-24 20:04

    鴻蒙原生頁面高性能解決方案上線OpenHarmony社區 助力打造高性能原生應用

    隨著HarmonyOS NEXT的正式推出,鴻蒙原生應用開發熱度高漲,數量激增。但在三方應用鴻蒙化進程中,性能問題頻出。為此,HarmonyOS NEXT推出了一整套原生頁面高性能解決方案,包括
    發表于 01-02 18:00

    Harmony如何管理網頁

    你好,我可能錯過了一些東西,但我找不到關于Harmony如何管理網頁(使用文件系統)以生成HTTP服務器中使用的c代碼的答案。我使用BSP和相關的評估板(PIC32MZ EC)啟動了一個項目。當生成
    發表于 07-30 12:25

    如何設置鴻蒙harmony控件的高度是屏幕的一半?

    鴻蒙harmony想讓控件的高度是屏幕的一半,該如何設置?在XML和java代碼中,分別該如何設置?
    發表于 03-23 11:09

    OpenHarmony應用ArkUI 狀態管理開發范例

    稱為狀態管理機制。 自定義組件擁有變量變量必須被裝飾器裝飾才可以成為狀態變量狀態變量的改變會
    發表于 09-01 15:03

    OpenHarmony頁面UI狀態存儲:LocalStorage

    LocalStorage是頁面的UI狀態存儲,通過@Entry裝飾器接收的參數可以在頁面內共享同一個LocalStorage實例。LocalStorage也可以在UIAbility內
    發表于 10-17 17:01

    鴻蒙 OS 應用開發初體驗

    kotlin 語言了,編程語言變成了類 JavaScript 的前端語言,這意味著我們需要適應用前端的思想去開發鴻蒙應用,比如狀態管理。 總結 本文純初體驗遙遙領先背后的鴻蒙操作系統
    發表于 11-02 19:38

    狀態變量濾波器,狀態變量濾波器原理是什么?

    狀態變量濾波器,狀態變量濾波器原理是什么? 狀態變量濾波器,又稱多態變量濾波器,它可以分別從不同的點同時輸出高通、帶通、低通等,且
    發表于 03-24 14:24 ?6665次閱讀

    華為p40升鴻蒙系統步驟教程

    華為鴻蒙(英語:Harmony OS,開發代號:Ark)是基于微內核的全場景分布式OS。
    的頭像 發表于 07-06 11:24 ?6154次閱讀

    Harmony 鴻蒙應用變量狀態管理

    應用變量狀態管理 在前面的章節中,已經講述了如何管理頁面
    的頭像 發表于 01-24 21:30 ?551次閱讀
    <b class='flag-5'>Harmony</b> <b class='flag-5'>鴻蒙</b>應用<b class='flag-5'>級</b><b class='flag-5'>變量</b>的<b class='flag-5'>狀態</b><b class='flag-5'>管理</b>
    真人百家乐软件云南景| 百家乐官网双筹码怎么出千| 娱乐百家乐下载| 百家乐官网娱乐网送68元| 钱大发888斗地主| 百家乐买隔一数| 乐九百家乐官网现金网| 百家乐影院| 娱乐城开户送钱| 游戏机百家乐的技术| 超级百家乐官网2龙虎斗| 上海德州扑克俱乐部| 赌场百家乐视频| 百家乐官网沙| 大发888老l| 真人百家乐代理合作| 百家乐官网赌场代理荐| 金都娱乐| 百家乐博娱乐场开户注册 | 香港六合彩论坛| 百家乐园鼎盛娱乐场| 百家乐官网透视牌靴| 皇冠平台| 百家乐平注法到656| 真人百家乐来博| 什么百家乐官网平注法| 集结号棋牌下载| 百家乐玩法皇冠现金网| 百家乐官网五星宏辉怎么玩| 英皇国际娱乐城| 大众百家乐娱乐城| 百家乐官网计划软件| 百家乐官网知敌便能制胜| 516棋牌游戏补丁| 百家乐赌场视屏| 做生意门口怎么摆放| 百家乐官网牌路分析仪| 衡山县| 顶级赌场官网| 金矿百家乐的玩法技巧和规则| 百家乐官网长t恤|