if/else:條件渲染
ArkTS提供了渲染控制的能力。條件渲染可根據(jù)應(yīng)用的不同狀態(tài),使用if、else和else if渲染對應(yīng)狀態(tài)下的UI內(nèi)容。
使用規(guī)則
- 支持if、else和else if語句。
- if、else if后跟隨的條件語句可以使用狀態(tài)變量。
- 允許在容器組件內(nèi)使用,通過條件渲染語句構(gòu)建不同的子組件。
- 條件渲染語句在涉及到組件的父子關(guān)系時(shí)是“透明”的,當(dāng)父組件和子組件之間存在一個(gè)或多個(gè)if語句時(shí),必須遵守父組件關(guān)于子組件使用的規(guī)則。
- 每個(gè)分支內(nèi)部的構(gòu)建函數(shù)必須遵循構(gòu)建函數(shù)的規(guī)則,并創(chuàng)建一個(gè)或多個(gè)組件。無法創(chuàng)建組件的空構(gòu)建函數(shù)會(huì)產(chǎn)生語法錯(cuò)誤。
- 某些容器組件限制子組件的類型或數(shù)量,將條件渲染語句用于這些組件內(nèi)時(shí),這些限制將同樣應(yīng)用于條件渲染語句內(nèi)創(chuàng)建的組件。例如,Grid容器組件的子組件僅支持GridItem組件,在Grid內(nèi)使用條件渲染語句時(shí),條件渲染語句內(nèi)僅允許使用GridItem組件。
更新機(jī)制
當(dāng)if、else if后跟隨的狀態(tài)判斷中使用的狀態(tài)變量值變化時(shí),條件渲染語句會(huì)進(jìn)行更新,更新步驟如下:
- 評估if和else if的狀態(tài)判斷條件,如果分支沒有變化,無需執(zhí)行以下步驟。如果分支有變化,則執(zhí)行2、3步驟:
- 刪除此前構(gòu)建的所有子組件。
- 執(zhí)行新分支的構(gòu)造函數(shù),將獲取到的組件添加到if父容器中。如果缺少適用的else分支,則不構(gòu)建任何內(nèi)容。
條件可以包括Typescript表達(dá)式。對于構(gòu)造函數(shù)中的表達(dá)式,此類表達(dá)式不得更改應(yīng)用程序狀態(tài)。
ForEach:循環(huán)渲染
ForEach接口基于數(shù)組類型數(shù)據(jù)來進(jìn)行循環(huán)渲染,需要與容器組件配合使用,且接口返回的組件應(yīng)當(dāng)是允許包含在ForEach父容器組件中的子組件。例如,ListItem組件要求ForEach的父容器組件必須為List組件。
接口描述
ForEach(
arr: Array,
itemGenerator: (item: any, index?: number) => void,
keyGenerator?: (item: any, index?: number) => string
)

鍵值生成規(guī)則
在ForEach循環(huán)渲染過程中,系統(tǒng)會(huì)為每個(gè)數(shù)組元素生成一個(gè)唯一且持久的鍵值,用于標(biāo)識(shí)對應(yīng)的組件。當(dāng)這個(gè)鍵值變化時(shí),ArkUI框架將視為該數(shù)組元素已被替換或修改,并會(huì)基于新的鍵值創(chuàng)建一個(gè)新的組件。
ForEach提供了一個(gè)名為keyGenerator的參數(shù),這是一個(gè)函數(shù),開發(fā)者可以通過它自定義鍵值的生成規(guī)則。如果開發(fā)者沒有定義keyGenerator函數(shù),則ArkUI框架會(huì)使用默認(rèn)的鍵值生成函數(shù),即(item: any, index: number) => { return index + '__' + JSON.stringify(item); }。
ArkUI框架對于ForEach的鍵值生成有一套特定的判斷規(guī)則,這主要與itemGenerator函數(shù)的第二個(gè)參數(shù)index以及keyGenerator函數(shù)的第二個(gè)參數(shù)index有關(guān),具體的鍵值生成規(guī)則判斷邏輯如下圖所示。
ForEach鍵值生成規(guī)則

注意:ArkUI框架會(huì)對重復(fù)的鍵值發(fā)出警告。在UI更新的場景下,如果出現(xiàn)重復(fù)的鍵值,框架可能無法正常工作,具體請參見渲染結(jié)果非預(yù)期。
組件創(chuàng)建規(guī)則
在確定鍵值生成規(guī)則后,F(xiàn)orEach的第二個(gè)參數(shù)itemGenerator函數(shù)會(huì)根據(jù)鍵值生成規(guī)則為數(shù)據(jù)源的每個(gè)數(shù)組項(xiàng)創(chuàng)建組件。組件的創(chuàng)建包括兩種情況:ForEach首次渲染和ForEach非首次渲染。
首次渲染
在ForEach首次渲染時(shí),會(huì)根據(jù)前述鍵值生成規(guī)則為數(shù)據(jù)源的每個(gè)數(shù)組項(xiàng)生成唯一鍵值,并創(chuàng)建相應(yīng)的組件。
@Entry
@Component
struct Parent {
@State simpleList: Array<string> = ['one', 'two', 'three'];
build() {
Row() {
Column() {
ForEach(this.simpleList, (item: string) => {
ChildItem({ item: item })
}, (item: string) => item)
}
.width('100%')
.height('100%')
}
.height('100%')
.backgroundColor(0xF1F3F5)
}
}
@Component
struct ChildItem {
@Prop item: string;
build() {
Text(this.item)
.fontSize(50)
}
}
非首次渲染
在ForEach組件進(jìn)行非首次渲染時(shí),它會(huì)檢查新生成的鍵值是否在上次渲染中已經(jīng)存在。如果鍵值不存在,則會(huì)創(chuàng)建一個(gè)新的組件;如果鍵值存在,則不會(huì)創(chuàng)建新的組件,而是直接渲染該鍵值所對應(yīng)的組件。例如,在以下的代碼示例中,通過點(diǎn)擊事件修改了數(shù)組的第三項(xiàng)值為"new three",這將觸發(fā)ForEach組件進(jìn)行非首次渲染。
@Entry
@Component
struct Parent {
@State simpleList: Array<string> = ['one', 'two', 'three'];
build() {
Row() {
Column() {
Text('點(diǎn)擊修改第3個(gè)數(shù)組項(xiàng)的值')
.fontSize(24)
.fontColor(Color.Red)
.onClick(() => {
this.simpleList[2] = 'new three';
})
ForEach(this.simpleList, (item: string) => {
ChildItem({ item: item })
.margin({ top: 20 })
}, (item: string) => item)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
}
.height('100%')
.backgroundColor(0xF1F3F5)
}
}
@Component
struct ChildItem {
@Prop item: string;
build() {
Text(this.item)
.fontSize(30)
}
}

從本例可以看出@State 能夠監(jiān)聽到簡單數(shù)據(jù)類型數(shù)組數(shù)據(jù)源 simpleList 數(shù)組項(xiàng)的變化。
- 當(dāng) simpleList 數(shù)組項(xiàng)發(fā)生變化時(shí),會(huì)觸發(fā) ForEach 進(jìn)行重新渲染。
- ForEach 遍歷新的數(shù)據(jù)源 ['one', 'two', 'new three'],并生成對應(yīng)的鍵值one、two和new three。
- 其中,鍵值one和two在上次渲染中已經(jīng)存在,所以 ForEach 復(fù)用了對應(yīng)的組件并進(jìn)行了渲染。對于第三個(gè)數(shù)組項(xiàng) "new three",由于其通過鍵值生成規(guī)則 item 生成的鍵值new three在上次渲染中不存在,因此 ForEach 為該數(shù)組項(xiàng)創(chuàng)建了一個(gè)新的組件。
使用建議
- 盡量避免在最終的鍵值生成規(guī)則中包含數(shù)據(jù)項(xiàng)索引index,以防止出現(xiàn)渲染結(jié)果非預(yù)期和渲染性能降低。如果業(yè)務(wù)確實(shí)需要使用index,例如列表需要通過index進(jìn)行條件渲染,開發(fā)者需要接受ForEach在改變數(shù)據(jù)源后重新創(chuàng)建組件所帶來的性能損耗。
- 為滿足鍵值的唯一性,對于對象數(shù)據(jù)類型,建議使用對象數(shù)據(jù)中的唯一id作為鍵值。
- 基本數(shù)據(jù)類型的數(shù)據(jù)項(xiàng)沒有唯一ID屬性。如果使用基本數(shù)據(jù)類型本身作為鍵值,必須確保數(shù)組項(xiàng)無重復(fù)。因此,對于數(shù)據(jù)源會(huì)發(fā)生變化的場景,建議將基本數(shù)據(jù)類型數(shù)組轉(zhuǎn)化為具備唯一ID屬性的對象數(shù)據(jù)類型數(shù)組,再使用ID屬性作為鍵值生成規(guī)則。