一、介紹
資料來(lái)自官網(wǎng):文檔中心
在聲明式UI編程框架中,UI是程序狀態(tài)的運(yùn)行結(jié)果,用戶構(gòu)建了一個(gè)UI模型,其中應(yīng)用的運(yùn)行時(shí)的狀態(tài)是參數(shù)。當(dāng)參數(shù)改變時(shí),UI作為返回結(jié)果,也將進(jìn)行對(duì)應(yīng)的改變。這些運(yùn)行時(shí)的狀態(tài)變化所帶來(lái)的UI的重新渲染,在ArkUI中統(tǒng)稱為狀態(tài)管理機(jī)制。
- View(UI):UI渲染,指將build方法內(nèi)的UI描述和@Builder裝飾的方法內(nèi)的UI描述映射到界面。
- State:狀態(tài),指驅(qū)動(dòng)UI更新的數(shù)據(jù)。用戶通過(guò)觸發(fā)組件的事件方法,改變狀態(tài)數(shù)據(jù)。狀態(tài)數(shù)據(jù)的改變,引起UI的重新渲染。
?
說(shuō)明:
@State裝飾器標(biāo)記的變量必須初始化,不能為空值
@State支持Object、class、string、number、boolean、enum類型以及這些類型的數(shù)組
嵌套類型以及數(shù)組中的對(duì)象屬性無(wú)法觸發(fā)視圖更新?
組件傳值代碼示例,為下面不同組件之間傳值做準(zhǔn)備:??
// 任務(wù)類
class Task{
static id: number = 1
// 任務(wù)名稱
name: string = `任務(wù)${Task.id++}`
// 任務(wù)狀態(tài):是否完成
finished: boolean = false
}
// 統(tǒng)一的卡片樣式
@Styles function card(){
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4})
}
@Entry
@Component
struct PropLinkPages {
// 總?cè)蝿?wù)數(shù)量
@State totalTask: number = 0
// 已完成任務(wù)數(shù)量
@State finishTask: number = 0
// 任務(wù)數(shù)組
@State tasks: Task[] = []
//此函數(shù)是更新任務(wù)總數(shù)量和已完成任務(wù)數(shù)量的
handleTaskChange(){
// 1.更新任務(wù)總數(shù)量
this.totalTask = this.tasks.length
// 2.更新已完成任務(wù)數(shù)量
this.finishTask = this.tasks.filter(item => item.finished).length
}
build() {
Column({space:10}){
//1.任務(wù)進(jìn)度卡片
Row(){
Text('任務(wù)進(jìn)度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
Stack(){
Progress({
value: this.finishTask,
total: this.totalTask,
type: ProgressType.Ring
})
.width(100)
Row(){
Text(this.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / ' + this.totalTask.toString())
.fontSize(24)
}
}
}
.card()
.margin({top: 5, bottom: 10})
.justifyContent(FlexAlign.SpaceEvenly)
// 2.新增任務(wù)按鈕
Button('新增任務(wù)')
.width(200)
.margin({bottom: 10})
.onClick(() => {
// 1.新增任務(wù)數(shù)據(jù)
this.tasks.push(new Task())
// 2.更新任務(wù)總數(shù)量
this.handleTaskChange()
})
//3.任務(wù)列表
List({space: 10}){
ForEach(
this.tasks,
(item: Task, index) => {
ListItem(){
Row(){
Text(item.name)
.fontSize(20)
Checkbox()
.select(item.finished)
.onChange(val => {
// 1.更新當(dāng)前任務(wù)狀態(tài)
item.finished = val
// 2.更新已完成任務(wù)數(shù)量
this.handleTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({end: this.DeleteButton(index)})
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
@Builder DeleteButton(index: number){
Button(){
Image($r('app.media.ic_public_delete_filled'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(() => {
this.tasks.splice(index, 1)
this.handleTaskChange()
})
}
}
示例代碼說(shuō)明:
這是一個(gè)展示任務(wù)進(jìn)度的效果,分為任務(wù)進(jìn)度條和任務(wù)列表兩部分
對(duì)于新增的任務(wù)勾選后可在任務(wù)進(jìn)度中查看已勾選和總?cè)蝿?wù)數(shù)量,左滑單個(gè)任務(wù)會(huì)出現(xiàn)刪除按鈕,可進(jìn)行此任務(wù)刪除操作
示例代碼的效果:
?
二、父子組件數(shù)據(jù)同步
2.1、@Prop裝飾器:父子單向同步
@Prop裝飾的變量可以和父組件建立單向的同步關(guān)系。@Prop裝飾的變量是可變的,但是變化不會(huì)同步回其父組件。
需求:將示例代碼中的任務(wù)進(jìn)度卡片封裝成TaskStatistics組件,在PropLinkPages組件中引入TaskStatistics組件,封裝后再完成數(shù)據(jù)的同步渲染
上面示例中:
父組件PropLinkPages,子組件TaskStatistics
總?cè)蝿?wù)與已完成任務(wù)數(shù)據(jù)是由父組件進(jìn)行維護(hù),子組件進(jìn)行渲染,所以需要父組件將數(shù)據(jù)傳遞給子組件
?使用@Prop,父子單向同步
@Prop只支持string、number、boolean、enum類型;父組件對(duì)象類型,子組件是對(duì)象屬性;不可以是數(shù)組、any
2.2、@Link裝飾器:父子雙向同步?
@Link裝飾的變量與其父組件中的數(shù)據(jù)源共享相同的值。
限制條件:@Link裝飾器不能在@Entry裝飾的自定義組件中使用
需求:將示例代碼中對(duì)任務(wù)數(shù)組的操作(新增任務(wù)與任務(wù)列表)封裝成TaskList組件,在PropLinkPages組件中引入TaskList組件
上面示例中:
父組件PropLinkPages,子組件TaskList
父子雙方都需要使用總認(rèn)為與已完成任務(wù)數(shù)據(jù),并且子組件的數(shù)據(jù)發(fā)生變化后需要通知父組件進(jìn)行變化,因?yàn)樯弦徊紷Prop時(shí)父組件需要將數(shù)據(jù)傳遞給另一個(gè)子組件TaskStatistics,所以涉及到父子雙向數(shù)據(jù)綁定渲染
?使用@Link,父子雙向同步
父子類型一致:string、number、boolean、enum、object、class,以及他們的數(shù)組;
數(shù)組中元素增、刪、替換會(huì)引起刷新
嵌套類型以及數(shù)組中的對(duì)象屬性無(wú)法觸發(fā)視圖更新
?三、后代組件雙向同步
3.1、@Provide裝飾器和@Consume裝飾器:與后代組件雙向同步
@Provide和@Consume,應(yīng)用于與后代組件的雙向數(shù)據(jù)同步,應(yīng)用于狀態(tài)數(shù)據(jù)在多個(gè)層級(jí)之間傳遞的場(chǎng)景。
需求:示例代碼中分別使用@Prop與@Link進(jìn)行數(shù)據(jù)傳遞,需要更改為@Provide和@Consume跨組件數(shù)據(jù)傳遞
上面示例中:
父組件PropLinkPages,子組件TaskList,子組件TaskStatistics
在父組件中使用@Provide將所需數(shù)據(jù)傳給兩個(gè)子組件,兩個(gè)子組件通過(guò)使用@Consume去獲取@Provide提供的變量,建立在@Provide和@Consume之間的雙向數(shù)據(jù)同步
?@Provide和@Consume可以通過(guò)相同的變量名或者相同的變量別名綁定,變量類型必須相同。
四、嵌套類對(duì)象屬性變化
4.1、@Observed裝飾器和@ObjectLink裝飾器:嵌套類對(duì)象屬性變化
對(duì)于多層嵌套的情況,比如二維數(shù)組,或者數(shù)組項(xiàng)class,或者class的屬性是class,他們的第二層的屬性變化是無(wú)法觀察到的。這就引出了@Observed/@ObjectLink裝飾器。
限制條件:
a:使用@Observed裝飾class會(huì)改變class原始的原型鏈,@Observed和其他類裝飾器裝飾同一個(gè)class可能會(huì)帶來(lái)問(wèn)題。
b:@ObjectLink裝飾器不能在@Entry裝飾的自定義組件中使用。
需求: 改造任務(wù)進(jìn)度的代碼,當(dāng)任務(wù)完成后,此任務(wù)置灰,并有中劃線
實(shí)現(xiàn)步驟:
①任務(wù)數(shù)組對(duì)應(yīng)的元素Task是對(duì)象類型,給Task對(duì)象添加@Observed裝飾器
②給嵌套的對(duì)象上所對(duì)應(yīng)的變量上添加@ObjectLink裝飾器,但源代碼中是方法參數(shù),所以將此段代碼封裝為TaskItem組件,在TaskItem組件中對(duì)變量item添加@ObjectLink
問(wèn)題:子組件需要調(diào)父組件的方法,把父組件的方法作為參數(shù)傳遞過(guò)來(lái),傳遞過(guò)程中存在this的丟失
解決:子組件中定義onTaskChange方法,傳遞給父組件時(shí)對(duì)函數(shù)使用bind方法將this傳遞進(jìn)去
如下:TaskItem({item:item,onTaskChange:this.handleTaskChange.bind(this)})
// 任務(wù)類
@Observed
class Task{
static id: number = 1
// 任務(wù)名稱
name: string = `任務(wù)${Task.id++}`
// 任務(wù)狀態(tài):是否完成
finished: boolean = false
}
// 統(tǒng)一的卡片樣式
@Styles function card(){
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4})
}
// 任務(wù)完成樣式
@Extend(Text) function finishedTask(){
.decoration({type:TextDecorationType.LineThrough})
.fontColor('#B1B2B1')
}
@Entry
@Component
struct PropLinkPages {
// 總?cè)蝿?wù)數(shù)量
@Provide totalTask: number = 0
// 已完成任務(wù)數(shù)量
@Provide finishTask: number = 0
build() {
Column({space:10}){
//1.任務(wù)進(jìn)度卡片
TaskStatistics()
//2.任務(wù)列表
TaskList()
}
.width('100%').height('100%').backgroundColor('#F1F2F3')
}
}
@Component
struct TaskList {
// 任務(wù)數(shù)組
@State tasks: Task[] = []
@Consume totalTask: number
@Consume finishTask: number
//此函數(shù)是更新任務(wù)總數(shù)量和已完成任務(wù)數(shù)量的
handleTaskChange(){
// 1.更新任務(wù)總數(shù)量
this.totalTask = this.tasks.length
// 2.更新已完成任務(wù)數(shù)量
this.finishTask = this.tasks.filter(item => item.finished).length
}
build() {
Column(){
// 2.新增任務(wù)按鈕
Button('新增任務(wù)')
.width(200)
.margin({bottom: 10})
.onClick(() => {
// 1.新增任務(wù)數(shù)據(jù)
this.tasks.push(new Task())
// 2.更新任務(wù)總數(shù)量
this.handleTaskChange()
})
//3.任務(wù)列表
List({space: 10}){
ForEach(
this.tasks,
(item: Task, index) => {
ListItem(){
TaskItem({item:item,onTaskChange:this.handleTaskChange.bind(this)})
}
.swipeAction({end: this.DeleteButton(index)})
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
@Builder DeleteButton(index: number){
Button(){
Image($r('app.media.ic_public_delete_filled'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(() => {
this.tasks.splice(index, 1)
this.handleTaskChange()
})
}
}
@Component
struct TaskStatistics {
@Consume totalTask: number
@Consume finishTask: number
build() {
Row(){
Text('任務(wù)進(jìn)度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
Stack(){
Progress({
value: this.finishTask,
total: this.totalTask,
type: ProgressType.Ring
})
.width(100)
Row(){
Text(this.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / ' + this.totalTask.toString())
.fontSize(24)
}
}
}.card().margin({top: 5, bottom: 10}).justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct TaskItem {
@ObjectLink item: Task
onTaskChange: () => void
build() {
Row(){
if(this.item.finished){
Text(this.item.name)
.finishedTask()
}else{
Text(this.item.name)
}
Checkbox()
.select(this.item.finished)
.onChange(val => {
// 1.更新當(dāng)前任務(wù)狀態(tài)
this.item.finished = val
// 2.更新已完成任務(wù)數(shù)量
this.onTaskChange()
})
}
.card()
.justifyContent(FlexAlign.SpaceBetween)
}
}
實(shí)現(xiàn)效果:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-832166.html
最后:??????????????文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-832166.html
到了這里,關(guān)于【鴻蒙系統(tǒng)學(xué)習(xí)筆記】狀態(tài)管理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!