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

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

3天內(nèi)不再提示

鴻蒙開發(fā)教程-管理組件狀態(tài)

jf_46214456 ? 2024-01-22 21:46 ? 次閱讀

概述

在應用中,界面通常都是動態(tài)的。如圖1所示,在子目標列表中,當用戶點擊目標一,目標一會呈現(xiàn)展開狀態(tài),再次點擊目標一,目標一呈現(xiàn)收起狀態(tài)。界面會根據(jù)不同的狀態(tài)展示不一樣的效果。

ArkUI作為一種聲明式UI,具有狀態(tài)驅(qū)動UI更新的特點。當用戶進行界面交互或有外部事件引起狀態(tài)改變時,狀態(tài)的變化會觸發(fā)組件自動更新。所以在ArkUI中,我們只需要通過一個變量來記錄狀態(tài)。當改變狀態(tài)的時候,ArkUI就會自動更新界面中受影響的部分。

ArkUI框架提供了多種管理狀態(tài)的裝飾器來修飾變量,使用這些裝飾器修飾的變量即稱為狀態(tài)變量。

在組件范圍傳遞的狀態(tài)管理常見的場景如下:

場景裝飾器
組件內(nèi)的狀態(tài)管理@State
從父組件單向同步狀態(tài)@Prop
與父組件雙向同步狀態(tài)@Link
跨組件層級雙向同步狀態(tài)@Provide和@Consume

在組件內(nèi)使用@State裝飾器來修飾變量,可以使組件根據(jù)不同的狀態(tài)來呈現(xiàn)不同的效果。若當前組件的狀態(tài)需要通過其父組件傳遞而來,此時需要使用@Prop裝飾器;若是父子組件狀態(tài)需要相互綁定進行雙向同步,則需要使用@Link裝飾器。使用@Provide和@Consume裝飾器可以實現(xiàn)跨組件層級雙向同步狀態(tài)。

在實際應用開發(fā)中,應用會根據(jù)需要封裝數(shù)據(jù)模型。如果需要觀察嵌套類對象屬性變化,需要使用@Observed和@ObjectLink裝飾器,因為上述表格中的裝飾器只能觀察到對象的第一層屬性變化。

另外,當狀態(tài)改變,需要對狀態(tài)變化進行監(jiān)聽做一些相應的操作時,可以使用@Watch裝飾器來修飾狀態(tài)。

組件內(nèi)的狀態(tài)管理:@State

實際開發(fā)中由于交互,組件的內(nèi)容呈現(xiàn)可能產(chǎn)生變化。當需要在組件內(nèi)使用狀態(tài)來控制UI的不同呈現(xiàn)方式時,可以使用@State裝飾器。以任務管理應用為例,當點擊子目標列表的其中一項,列表項會展開。當再次點擊同一項,列表項會收起。所以,對于某一個列表項來說,它的呈現(xiàn)方式會受列表項是否展開這個狀態(tài)影響。

將是否展開這個狀態(tài)定義為isExpanded變量,當其值為false表示目標項收起,值為true時表示目標項展開。

此時,需要使用@State裝飾器修飾isExpanded,使其成為目標項內(nèi)部的狀態(tài)變量。通過@State裝飾后,框架內(nèi)部會建立數(shù)據(jù)與視圖間的綁定,

當isExpanded狀態(tài)變化時,目標項會隨之展開或收起。

其具體實現(xiàn)只要用@State修飾isExpanded變量,定義是否展開狀態(tài)。然后通過條件渲染,實現(xiàn)是否顯示進度調(diào)整面板和列表項的高度變化。最后,監(jiān)聽列表項的點擊事件,在onClick回調(diào)中改變isExpanded狀態(tài)。

這樣就實現(xiàn)了對相同列表項點擊時,列表項的展開和收起功能。當用戶反復點擊同一個列表項時,組件內(nèi)的isExpanded狀態(tài)變化,列表項會自動更新。

@Component
export default struct TargetListItem {
  @State isExpanded: boolean = false;
  ...

  build() {
    ...
      Column() {
        ...
        if (this.isExpanded) {
          Blank()
          ProgressEditPanel(...)
        }
      }
      .height(this.isExpanded ? $r('app.float.expanded_item_height')                  
      : $r('app.float.list_item_height'))
      .onClick(() = > {
        ...
             this.isExpanded = !this.isExpanded;
        ...
       })
    ...
  }
}

從父組件單向同步狀態(tài):@Prop

當子組件中的狀態(tài)依賴從父組件傳遞而來時,需要使用@Prop裝飾器,@Prop修飾的變量可以和其父組件中的狀態(tài)建立單向同步關系。當父組件中狀態(tài)變化時,該狀態(tài)值也會更新至@Prop修飾的變量;對@Prop修飾的變量的修改不會影響其父組件中的狀態(tài)。

圖4 列表的編輯模式

如圖4所示,在目標管理應用中,當用戶點擊子目標列表的“編輯”文本,列表進入編輯模式,點擊取消,列表退出編輯模式。

整個列表是自定義組件TargetList,頂部是文本顯示區(qū)域,主要是Text組件,底部是一個Button組件。中間區(qū)域則是用來顯示每個目標項,目標項是自定義組件TargetListItem。

從圖中可以看出,TargetListItem是TargetList的子組件。TargetList是TargetListItem父組件。

圖5 TargetList和TargetListItem

對于父組件TargetList,其頂部顯示的文本和底部按鈕會隨編輯模式的變化而變化,因此父組件擁有編輯模式狀態(tài)。

對于子組件TargetListItem,其最右側(cè)是否預留位置和顯示勾選框也會隨編輯模式變化,因此子組件也擁有編輯模式狀態(tài)。

但是是否進入編輯模式,其觸發(fā)點是在用戶點擊列表的“編輯”或取消按鈕,狀態(tài)變化的源頭僅在于父組件TargetList。當父組件TargetList中的編輯模式變化時,子組件TargetListItem的編輯模式狀態(tài)需要隨之變化。

圖6 從父組件單向同步isEditMode狀態(tài)

在父組件TargetList中可以定義一個是否進入編輯模式的狀態(tài),即用@State修飾isEditMode。@State修飾的變量不僅是組件內(nèi)部的狀態(tài),也可以作為子組件單向或雙向同步的數(shù)據(jù)源。ArkUI提供了@Prop裝飾器,@Prop修飾的變量可以和其父組件中的狀態(tài)建立單向同步關系,所以用@Prop修飾子組件TargetListItem中的isEditMode變量。

在父組件TargetList中,用@State修飾isEditMode,定義編輯模式狀態(tài)。然后利用條件渲染實現(xiàn)根據(jù)是否進入編輯模式,顯示不同的文本和按鈕。同時,在父組件中需要在用戶點擊時改變狀態(tài),觸發(fā)界面更新。

當點擊“編輯”事件發(fā)生時,進入編輯模式,顯示取消、全選文本和勾選框,同時顯示刪除按鈕;當點擊“取消”事件發(fā)生時,退出編輯模式,顯示“編輯”文本和“添加子目標”按鈕。

@Component
export default struct TargetList {
  @State isEditMode: boolean = false;
  ...
  build() {
    Column() {
      Row() {
        ...
          if (this.isEditMode) {
            Text($r('app.string.cancel_button'))
              .onClick(() = > {
                this.isEditMode = false;
                ...
               })
               ...
            Text($r('app.string.select_all_button'))...
            Checkbox()...
          } else {
            Text($r('app.string.edit_button'))
              .onClick(() = > {
                this.isEditMode = true;
              })
              ...
          }
        ...
      }
      ...
      List({ space: CommonConstants.LIST_SPACE }) {
        ForEach(this.targetData, (item: TaskItemBean, index: number) = > {
          ListItem() {
            TargetListItem({
              isEditMode: this.isEditMode,
              ...
            })
          }
        }, (item, index) = > JSON.stringify(item) + index)
      }
      ...
      if (this.isEditMode) {
        Button($r('app.string.delete_button'))
      } else {
        Button($r('app.string.add_task'))
      }
    }
    ...
  }
}

在子組件TargetListItem中,使用@Prop修飾子組件的isEditMode變量,定義子組件的編輯模式狀態(tài)。然后同樣根據(jù)是否進入編輯模式,控制目標項最右側(cè)是否預留位置和顯示勾選框。

@Component
export default struct TargetListItem {
   @Prop isEditMode: boolean;
   ...
       Column() {
        ...
       }
       .padding({
        ...
        right: this.isEditMode ? $r('app.float.list_edit_padding') 
               : $r('app.float.list_padding')
       })
       ...

       if (this.isEditMode) {
        Row() {
           Checkbox()...
        }
       }
  ...
}

最后,最關鍵的一步就是要在父組件中使用子組件時,將父組件的編輯模式狀態(tài)this.isEditMode傳遞給子組件的編輯模式狀態(tài)isEditMode。

@Component
export default struct TargetList {
  @State isEditMode: boolean = false;
  ...
  build() {
    Column() {
      ...
      List({ space: CommonConstants.LIST_SPACE }) {
        ForEach(this.targetData, (item: TaskItemBean, index: number) = > {
          ListItem() {
            TargetListItem({
              isEditMode: this.isEditMode,
              ...
            })
          }
        }, (item, index) = > JSON.stringify(item) + index)
      }
      ...
    }
    ...
  }
}

與父組件雙向同步狀態(tài):@Link

若是父子組件狀態(tài)需要相互綁定進行雙向同步時,可以使用@Link裝飾器。父組件中用于初始化子組件@Link變量的必須是在父組件中定義的狀態(tài)變量。

圖7 切換目標項

在目標管理應用中,當用戶點擊同一個目標,目標項會展開或者收起。當用戶點擊不同的目標項時,除了被點擊的目標項展開,同時前一次被點擊的目標項會收起。

如圖7所示,當目標一展開時,點擊目標三,目標三會展開,同時目標一會收起。再點擊目標一時,目標一展開,同時目標三會收起。

從目標一切換到目標三的流程中,關鍵在于最后目標一的收起,當點擊目標三時,目標一需要知道點擊了目標三,目標一才會收起。

圖8 子目標列表目標項位置索引

在子目標列表中,每個列表項都有其位置索引值index屬性,表示目標項在列表中的位置。index從0開始,即第一個目標項的索引值為0,第二個目標項的索引值為1,以此類推。此外,clickIndex用來記錄被點擊的目標項索引。當點擊目標一時,clickIndex為0,點擊目標三時,clickIndex為2。

在父組件子目標列表和每個子組件目標項中都擁有clickIndex狀態(tài)。當目標一展開時,clickIndex為0。此時點擊目標三,目標三的clickIndex變?yōu)?,只要其父組件子目標列表感知到clickIndex狀態(tài)變化,同時將此變化傳遞給目標一。目標一的clickIndex即可同步改變?yōu)?,即目標一感知到此時點擊了目標三。

圖9 與父組件雙向同步clickIndex狀態(tài)

將列表和目標項對應到列表組件TargetList和列表項TargetListItem。首先,需要在父組件TargetList中定義clickIndex狀態(tài)。

若此時子組件中的clickIndex用@Prop裝飾器修飾,當子組件中clickIndex變化時,父組件無法感知,因為@Prop裝飾器建立的是從父組件到子組件的單向同步關系。

ArkUI提供了@Link裝飾器,用于與父組件雙向同步狀態(tài)。當子組件TargetListItem中的clickIndex用@Link修飾,可與父組件TargetList中的clickIndex建立雙向同步關系。

@Component
export default struct TargetList {
  @State clickIndex: number = CommonConstants.DEFAULT_CLICK_INDEX;
  ...
             TargetListItem({
               clickIndex: $clickIndex,
              ...
             })
  ...
}

首先,在父組件TargetList中用@State裝飾器定義點擊的目標項索引狀態(tài)。然后,在子組件TargetListItem中用@Link裝飾器定義clickIndex,當點擊目標項時,clickIndex更新為當前目標索引值。

完成在父子組件中定義狀態(tài)后,最關鍵的就是要建立父子組件的雙向關聯(lián)關系。在父組件中使用子組件時,將父組件的clickIndex傳遞給子組件的clickIndex。其中父組件的clickIndex加上$表示傳遞的是引用。

@Component
export default struct TargetListItem {
  @Link @Watch('onClickIndexChanged') clickIndex: number;
  @State isExpanded: boolean = false
  ...

  onClickIndexChanged() {
    if (this.clickIndex != this.index) {
      this.isExpanded = false;
    }
  }

  build() {
    ...
       Column() {
        ...
       }
       .onClick(() = > {
        ...
           this.clickIndex = this.index;
        ...
       })
    ...
  }
}

當目標一感知到點擊了目標三時,還需要將目標一收起,切換列表項的功能才是完整的。此時,目標一感知到clickIndex變?yōu)?,需要判斷與目標一本身的位置索引值0不相等,從而將目標一收起。此時,就需要用到ArkUI中監(jiān)聽狀態(tài)變化@Watch的能力。用@Watch修飾的狀態(tài),當狀態(tài)發(fā)生變化時,會觸發(fā)聲明時定義的回調(diào)。

我們給TargetListItem的中的clickIndex狀態(tài)加上@Watch("onClickIndexChanged")。這表示需要監(jiān)聽clickIndex狀態(tài)的變化。當clickIndex狀態(tài)變化時,將觸發(fā)onClickIndexChanged回調(diào):如果點擊的列表項索引不等于當前列表項索引,則將isExpanded狀態(tài)置為false,從而收起該目標項。

跨組件層級雙向同步狀態(tài):@Provide和@Consume

跨組件層級雙向同步狀態(tài)是指@Provide修飾的狀態(tài)變量自動對提供者組件的所有后代組件可用,后代組件通過使用@Consume裝飾的變量來獲得對提供的狀態(tài)變量的訪問。@Provide作為數(shù)據(jù)的提供方,可以更新其子孫節(jié)點的數(shù)據(jù),并觸發(fā)頁面渲染。@Consume在感知到@Provide數(shù)據(jù)的更新后,會觸發(fā)當前自定義組件的重新渲染。

使用@Provide的好處是開發(fā)者不需要多次將變量在組件間傳遞。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 組件
    +關注

    關注

    1

    文章

    503

    瀏覽量

    17786
  • 鴻蒙
    +關注

    關注

    57

    文章

    2302

    瀏覽量

    42689
  • OpenHarmony
    +關注

    關注

    25

    文章

    3640

    瀏覽量

    16061
收藏 人收藏

    評論

    相關推薦

    HarmonyOS實戰(zhàn)開發(fā)-如何使用全局狀態(tài)保留能力彈窗來實現(xiàn)評論組件。

    層-短視頻切換 ||---CommentView.ets // 視圖層-評論組件 模塊依賴 路由模塊:供entry模塊實現(xiàn)路由導航 公共模塊:全局狀態(tài)保留能力彈窗 最后 如果大家覺得這篇內(nèi)容對學習鴻蒙
    發(fā)表于 05-07 15:06

    HarmonyOS實戰(zhàn)開發(fā)-全局狀態(tài)保留能力彈窗

    // 全局狀態(tài)保留能力彈窗 模塊依賴 不涉及 最后 如果大家覺得這篇內(nèi)容對學習鴻蒙開發(fā)有幫助,我想邀請大家?guī)臀胰齻€小忙: 點贊,轉(zhuǎn)發(fā),有你們的 『點贊和評論』,才是我創(chuàng)造的動力。 關注小編,同時可以
    發(fā)表于 05-07 14:53

    HarmonyOS開發(fā)實例:【狀態(tài)管理

    從數(shù)據(jù)的傳遞形式來看,可以分為只讀的單向傳遞和可變更的雙向傳遞。如下圖所示,開發(fā)框架提供了多種應用程序狀態(tài)管理的能力。
    的頭像 發(fā)表于 04-10 09:38 ?757次閱讀
    HarmonyOS<b class='flag-5'>開發(fā)</b>實例:【<b class='flag-5'>狀態(tài)</b><b class='flag-5'>管理</b>】

    鴻蒙OS開發(fā)實例:【組件化模式】

    組件化一直是移動端比較流行的開發(fā)方式,有著編譯運行快,業(yè)務邏輯分明,任務劃分清晰等優(yōu)點,針對Android端的組件化;與Android端的組件化相比,HarmonyOS的
    的頭像 發(fā)表于 04-07 17:44 ?571次閱讀
    <b class='flag-5'>鴻蒙</b>OS<b class='flag-5'>開發(fā)</b>實例:【<b class='flag-5'>組件</b>化模式】

    鴻蒙OS開發(fā)實例:【應用狀態(tài)變量共享】

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

    鴻蒙實戰(zhàn)項目開發(fā):【短信服務】

    兩位前阿里高級研發(fā)工程師聯(lián)合打造的 《鴻蒙NEXT星河版OpenHarmony開發(fā)文檔》 里面內(nèi)容包含了(ArkTS、ArkUI開發(fā)組件、Stage模型、多端部署、分布式應用
    發(fā)表于 03-03 21:29

    使用 Taro 開發(fā)鴻蒙原生應用 —— 快速上手,鴻蒙應用開發(fā)指南

    隨著鴻蒙系統(tǒng)的不斷完善,許多應用廠商都希望將自己的應用移植到鴻蒙平臺上。最近,Taro 發(fā)布了 v4.0.0-beta.x 版本,支持使用 Taro 快速開發(fā)鴻蒙原生應用,也可將現(xiàn)有的
    的頭像 發(fā)表于 02-02 16:09 ?803次閱讀
    使用 Taro <b class='flag-5'>開發(fā)</b><b class='flag-5'>鴻蒙</b>原生應用 —— 快速上手,<b class='flag-5'>鴻蒙</b>應用<b class='flag-5'>開發(fā)</b>指南

    Harmony 鴻蒙頁面級變量的狀態(tài)管理

    頁面級變量的狀態(tài)管理 @State、@Prop、@Link、@Provide、@Consume、@ObjectLink、@Observed和@Watch用于管理頁面級變量的狀態(tài)。 @S
    的頭像 發(fā)表于 01-25 10:42 ?538次閱讀
    Harmony <b class='flag-5'>鴻蒙</b>頁面級變量的<b class='flag-5'>狀態(tài)</b><b class='flag-5'>管理</b>

    Harmony 鴻蒙應用級變量的狀態(tài)管理

    應用級變量的狀態(tài)管理 在前面的章節(jié)中,已經(jīng)講述了如何管理頁面級變量的狀態(tài),本章將說明如何管理應用級變量的
    的頭像 發(fā)表于 01-24 21:30 ?448次閱讀
    Harmony <b class='flag-5'>鴻蒙</b>應用級變量的<b class='flag-5'>狀態(tài)</b><b class='flag-5'>管理</b>

    Harmony 鴻蒙頁面級變量的狀態(tài)管理

    += 1 }) } } @Observed和ObjectLink數(shù)據(jù)管理開發(fā)者需要在子組件中針對父組件的一個變量(parent_a)設置雙向同步時,
    發(fā)表于 01-24 20:04

    鴻蒙ArkUI開發(fā)-Video組件的使用

    以視頻功能為例,在應用開發(fā)過程中,我們需要通過ArkUI提供的Video組件為應用增加基礎的視頻播放功能。借助Video組件,我們可以實現(xiàn)視頻的播放功能并控制其播放狀態(tài)。常見的視頻播放
    的頭像 發(fā)表于 01-23 16:59 ?1210次閱讀
    <b class='flag-5'>鴻蒙</b>ArkUI<b class='flag-5'>開發(fā)</b>-Video<b class='flag-5'>組件</b>的使用

    鴻蒙ArkUI開發(fā)-Tabs組件的使用

    鴻蒙ArkUI開發(fā)-Tabs組件的使用
    的頭像 發(fā)表于 01-19 16:01 ?1704次閱讀
    <b class='flag-5'>鴻蒙</b>ArkUI<b class='flag-5'>開發(fā)</b>-Tabs<b class='flag-5'>組件</b>的使用

    鴻蒙開發(fā)-ArkUI 組件基礎

    1 組件介紹 組件(Component)是界面搭建與顯示的最小單位,HarmonyOS ArkUI聲明式開發(fā)范式為開發(fā)者提供了豐富多樣的UI組件
    發(fā)表于 01-17 19:31

    鴻蒙開發(fā)OpenHarmony組件復用案例

    概述 在開發(fā)應用時,有些場景下的自定義組件具有相同的組件布局結構,僅有狀態(tài)變量等承載數(shù)據(jù)的差異。這樣的組件緩存起來,需要使用到該
    發(fā)表于 01-15 17:37

    鴻蒙開發(fā)基礎-Web組件之cookie操作

    }) ... } ... 本文章主要是對鴻蒙開發(fā)當中ArkTS語言的基礎應用實戰(zhàn),Web組件里的cookie操作。更多的鴻蒙應用開發(fā)
    發(fā)表于 01-14 21:31