ArkUI開發框架提供了多維度的狀態管理機制,和UI相關聯的數據,不僅可以在組件內使用,還可以在不同組件層級間傳遞,比如父子組件之間,爺孫組件之間等,也可以是全局范圍內的傳遞,還可以是跨設備傳遞。另外,從數據的傳遞形式來看,可以分為只讀的單向傳遞和可變更的雙向傳遞。如下圖所示,開發框架提供了多種應用程序狀態管理的能力。
@State修飾符
@State
裝飾的變量是組件內部的狀態數據,當這些狀態數據被修改時,將會調用所在組件的 build()
方法刷新UI。 @State
狀態數據具有以下特征:
- 支持多種數據類型:允許
class
、number
、boolean
、string
強類型的按值和按引用類型。允許這些強類型構成的數組,即Array
、Array
、Array
、Array
。不允許object
和any
。 - 內部私有:標記為
@State
的屬性是私有變量,只能在組件內訪問。 - 支持多個實例:組件不同實例的內部狀態數據獨立。
- 需要本地初始化:必須為所有
@State
變量分配初始值,將變量保持未初始化可能導致框架行為未定義,初始值需要是有意義的值,比如設置class
類型的值為null
就是無意義的,會導致編譯報錯。 - 創建自定義組件時支持通過狀態變量名設置初始值:在創建組件實例時,可以通過變量名顯式指定
@State
狀態屬性的初始值。
|
簡單樣例如下所示:
@Entry @Component struct ComponentTest {
@State date: string = "時間:" + new Date().getTime(); // data變化會觸發build方法執行
build() {
Column({space: 10}) {
Text(`父組件【${this.date}】`) // 顯示時間
.fontSize(20)
.backgroundColor(Color.Pink)
Item() // 子組件
Item() // 子組件
Button('更新時間')
.onClick(() = > {
this.date = "時間:" + new Date().getTime(); // 點擊按鈕,date變化,會觸發build方法執行
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
// 自定義子組件
@Component struct Item {
@State time: string = "時間:" + new Date().getTime();
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = "時間:" + new Date().getTime(); // 點擊更新時間,執行build方法
})
}
}
樣例運行結果如下圖所示:
@Prop修飾符
開發應用知識已更新[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md
]參考前往。
@Prop
與 @State
有相同的語義,但初始化方式不同, @Prop
裝飾的變量可以和父組件的 @State
變量建立單向的數據綁定。即 @Prop
修飾的變量必須使用其父組件提供的 @State
變量進行初始化,允許組件內部修改 @Prop
變量值但更改不會通知給父組件。 @Prop
狀態數據具有以下特征:
支持簡單數據類型:僅支持
number
、string
、boolean
簡單類型;內部私有:標記為
@Prop
的屬性是私有變量,只能在組件內訪問。支持多個實例:組件不同實例的內部狀態數據獨立。
不支持內部初始化:在創建組件的新實例時,必須將值傳遞給
@Prop
修飾的變量進行初始化,不支持在組件內部進行初始化。
簡單樣例如下所示:@Entry @Component struct ComponentTest { @State date: string = "時間:" + new Date().getTime(); build() { Column({space: 10}) { Text(`父組件【${this.date}】`) .fontSize(20) .backgroundColor(Color.Pink) Item({time: this.date}) // 必須初始化子組件的time字段 Item({time: this.date}) // 必須初始化子組件的time字段 Button('更新時間') .onClick(() = > { this.date = "時間:" + new Date().getTime();// 父組件的更改影響子組件 }) } .width('100%') .height('100%') .padding(10) } } @Component struct Item { @Prop time: string; // 不允許本地初始化 build() { Text(`子組件【${this.time}】`) .fontSize(20) .backgroundColor(Color.Grey) .onClick(() = > { this.time = "時間:" + new Date().getTime(); // 子組件的更改不影響父組件 }) } }
樣例運行結果如下圖所示:
@Link修飾符
@Link
與 @State
有相同的語義,但初始化方式不同, @Link
裝飾的變量可以和父組件的 @State
變量建立雙向的數據綁定。即 @Link
修飾的變量必須使用其父組件提供的 @State
變量進行初始化,允許組件內部修改 @Link
變量值且更改會通知給父組件。 @Link
狀態數據具有以下特征:
- 支持多種數據類型:
@Link
變量的值與@State
變量的類型相同,即class
、number
、string
、boolean
或這些類型的數組。 - 內部私有:標記為
@Link
的屬性是私有變量,只能在組件內訪問。 - 支持多個實例:組件不同實例的內部狀態數據獨立。
- 不支持內部初始化:在創建組件的新實例時,必須將值傳遞給
@Link
修飾的變量進行初始化,不支持在組件內部進行初始化。初始化使用$
符號,例如:$propertiesName。
樣例如下:
@Entry @Component struct ComponentTest {
@State date: string = "時間:" + new Date().getTime(); // 定義@State變量
build() {
Column({space: 10}) {
Text(`父組件【${this.date}】`)
.fontSize(20)
.backgroundColor(Color.Pink)
Item({time: $date}) // 初始化子組件time屬性使用$符號
Item({time: $date}) // 初始化子組件time屬性使用$符號
Button('更新時間')
.onClick(() = > {
this.date = "時間:" + new Date().getTime(); // 變更date,子組件的對應屬性也變化
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
@Component struct Item {
@Link time: string;
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = "時間:" + new Date().getTime(); // 變更time,父組件的對應屬性也變化
})
}
}
樣例運行結果如下圖所示:
@StorageLink修飾符
@StorageLink(key)
裝飾的變量是組件內部的狀態數據,當這些狀態數據被修改時,將會調用所在組件的 build()
方法進行UI刷新。組件通過使用 @StorageLink(key)
裝飾的狀態變量與 AppStorage
建立雙向數據綁定。當創建包含 @StorageLink
的狀態變量的組件時,該狀態變量的值將使用 AppStorage
中的值進行初始化,在UI組件中對 @StorageLink
的狀態變量所做的更改將同步到 AppStorage
,并從 AppStorage
同步到任何其他綁定實例中,如 PersistentStorage
或其他綁定的UI組件。 @StorageLink
狀態數據具有以下特征:
- 支持多種數據類型:支持的數據類型和
@State
一致且支持object
。 - 需要本地初始化:必須為所有
@StorageLink
變量分配初始值。 - 數據狀態全局化:使用
@StorageLink
修飾的數據變化后全局都會改變。 - 數據持久化:通過搭配
PersistentStorage
接口實現數據持久化。- 綁定數據
簡單樣例如下所示:@Entry @Component struct ComponentTest { @StorageLink('time') time: string = "1648643734154";// 使用StorageLink標記并初始化 build() { Column({space: 10}) { Text(`父組件【${this.time}】`) // 使用time值 .fontSize(20) .backgroundColor(Color.Pink) Button('更新時間') .onClick(() = > { this.time = new Date().getTime().toString();// 更改time的值 }) } .width('100%') .height('100%') .padding(10) } }
- 綁定數據
運行結果如下圖所示:
- **雙向綁定數據**
簡單樣例如下所示:
```
@Entry @Component struct ComponentTest {
@StorageLink('time') time1: string = "1648643734154";
@StorageLink('time') time2: string = "abcdefefwefwewee";
build() {
Column({space: 10}) {
Text(`父組件【${this.time1}】`)
.fontSize(20)
.backgroundColor(Color.Pink)
Item();
Item();
Button('更新時間')
.onClick(() = > {
this.time2 = new Date().getTime().toString();
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
@Component struct Item {
@StorageLink('time') time: string = "OpenHarmony";
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = new Date().getTime().toString();
})
}
}
```
運行結果如下圖所示:
- 頁面間數據綁定
簡單樣例如下圖所示:
// 第一個頁面
@Entry @Component struct ComponentTest {
@StorageLink('time') time1: string = "1648643734154";// 應用key的值以首次初始化的值為準
@StorageLink('time') time2: string = "abcdefefwefwewee";// time2以time1的值為準
build() {
Column({space: 10}) {
Text(`父組件【${this.time1}】`)
.fontSize(20)
.backgroundColor(Color.Pink)
Item();// 使用自定義組件
Item();// 使用自定義組件
Button('更新時間')
.onClick(() = > {
this.time2 = new Date().getTime().toString();// 更改time2的值,所有使用key的頁面都會刷新
})
Button('跨頁面數據綁定')
.onClick(() = > {
router.push({uri: "pages/test/setting"})// 打開第二個頁面
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
// 自定義個組件
@Component struct Item {
@StorageLink('time') time: string = "OpenHarmony";// time的值以key第一次出現的初始化為準
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = new Date().getTime().toString();// 更改time的值,所有使用key的頁面都會刷新
})
}
}
// 第二個頁面
@Entry @Component struct Setting {
@StorageLink('time') tips: string = "我是第二個頁面"; // tips的值以'key'第一次出現的為準
build() {
Column({space: 10}) {
Text(this.tips) // tips的值以'key'第一次出現的為準
.fontSize(20)
.margin(20)
.onClick(() = > {
this.tips = "0000000000000" // 更改tips的值,所有使用key的頁面都會更新
})
Button('返回')
.onClick(() = > {
router.back()// 點擊返回,首頁的數據會更改
})
}
.width('100%')
.height('100%')
}
}
運行結果如下圖所示:
- 持久化數據
@StorageLink
搭配 PersistentStorage
接口可以實現數據本地持久化,簡單樣例如下圖所示:
// 持久化存儲key并設置默認值
PersistentStorage.PersistProp("time", "Hello, OpenHarmony")
@Entry @Component struct ComponentTest {
// 初始化time1,如果AppStorage
@StorageLink('time') time1: string = "1648643734154";
@StorageLink('time') time2: string = "OpenHarmony";
build() {
Column({space: 10}) {
Text(`父組件【${this.time1}】`)
.fontSize(20)
.backgroundColor(Color.Pink)
Item();
Item();
Button('更新時間')
.onClick(() = > {
this.time2 = new Date().getTime().toString();
})
Button('跨頁面數據綁定')
.onClick(() = > {
router.push({uri: "pages/test/setting"})
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
// 自定義組件
@Component struct Item {
@StorageLink('time') time: string = "OpenHarmony";
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = new Date().getTime().toString();
})
}
}
運行結果如下圖所示:
@Watch修飾符
@Watch
用來監聽狀態變量的變化,當它修飾的狀態變量發生變更時,回調相應的方式,語法結構為:
@State @Watch("function_name") count : number = 0;
上述語句表示:給狀態變量 count
增加一個 @Watch
裝飾器,通過 @Watch
注冊一個回調方法 function_name
, 當狀態變量 count
被改變時, 觸發 function_name
回調。
簡單樣例如下所示:
@Entry @Component struct WatchTest {
@State @Watch("onBasketUpdated") shopBasket: Array< number > = [7, 12, 47, 3];
@State totalPurchase: number = 0;
updateTotal(): number {
let sum = 0;
this.shopBasket.forEach((i) = > {
sum += i;
});
// 計算新的購物籃總價值,如果超過100RMB,則適用折扣
this.totalPurchase = (sum < 100) ? sum : 0.9 * sum;
return this.totalPurchase;
}
onBasketUpdated(propName: string): void {
this.updateTotal();
}
build() {
Column({space: 10}) {
Text(`${this.totalPurchase}`)
.fontSize(30)
Button("add to basket")
.onClick(() = > {
this.shopBasket.push(Math.round(100 * Math.random()))
})
}
.width("100%")
.height("100%")
.padding(10)
}
}
樣例運行結果如下圖所示:
集合 shopBasket
是一個狀態變量,它被 @Watch
修飾符修飾并綁定了 onBasketUpdated()
方法回調,當點擊按鈕往 shopBasket
里添加數據時會觸發 onBasketUpdated()
方法的調用,該方法里邊執行了 totalPurchase
的數據計算,最后頁面刷新。
@Watch
裝飾器只能監聽 @State
、 @Prop
、 @Link
、 @ObjectLink
、 @Provide
、 @Consume
、 @StorageProp
以及 @StorageLink
裝飾的變量。
小結
通過對ArkUI三種狀態管理的介紹,可以根據具體的業務場景選擇不同的狀態管理模式。
審核編輯 黃宇
-
鴻蒙
+關注
關注
57文章
2365瀏覽量
42894 -
HarmonyOS
+關注
關注
79文章
1978瀏覽量
30273 -
OpenHarmony
+關注
關注
25文章
3727瀏覽量
16382
發布評論請先 登錄
相關推薦
評論