【高心星出品】
Repeat組件的使用
概念
Repeat基於數組類型數據來進行循環渲染,一般與容器組件配合使用。
Repeat根據容器組件的有效加載範圍(屏幕可視區域+預加載區域)加載子組件。當容器滑動/數組改變時,Repeat會根據父容器組件的佈局過程重新計算有效加載範圍,並管理列表子組件節點的創建與銷燬。
-
Repeat必須在滾動類容器組件內使用,僅有List、ListItemGroup、Grid、Swiper以及WaterFlow組件支持Repeat懶加載場景。
循環渲染只允許創建一個子組件,子組件應當是允許包含在容器組件中的子組件。例如:Repeat與List組件配合使用時,子組件必須為ListItem組件。
- Repeat不支持V1裝飾器,混用V1裝飾器會導致渲染異常。
- Repeat當前不支持動畫效果。
- 滾動容器組件內只能包含一個Repeat。以List為例,不建議同時包含ListItem、ForEach、LazyForEach,不建議同時包含多個Repeat。
- 當Repeat與自定義組件或@Builder函數混用時,必須將RepeatItem類型整體進行傳參,組件才能監聽到數據變化。詳見Repeat與@Builder混用。
Repeat子組件由.each()和.template()屬性定義,只允許包含一個子組件。當頁面首次渲染時,Repeat根據當前的有效加載範圍(屏幕可視區域+預加載區域)按需創建子組件。如下圖所示:
repeat默認會分配1個預加載節點,通過cachecount可以認為調整預加載節點個數。
案例
repeat全量加載數組案例:
下面案例使用list加載全量數組元素,第一運行的時候就會把100個listitem都渲染出來,耗費時間和內存。
日誌輸入結果:
// 父組件使用Repeat渲染列表
@Entry
@Component
struct repeatpage {
@State items: string[] = [];
aboutToAppear() {
// 初始化數據
for (let i = 0; i < 100; i++) {
this.items.push(`列表項 ${i}`);
}
}
build() {
List() {
Repeat(this.items)
// 遍歷每個數組元素
.each((item: RepeatItem<string>) => {
ListItem() {
Text(item.item)
.fontSize(20)
.width('100%')
.textAlign(TextAlign.Center)
}.onAppear(()=>{
// 當listitem渲染的時候調用
console.log('gxxt ',item.item+' 出現了')
})
})
}
.width('100%')
}
}
repeat開啓懶加載和設置預加載數量
下面案例開啓了virtualScroll懶加載和cachedCount預加載數量,可以看到第一次只渲染了可見區域的listitem,隨着滑動重用預加載的節點。第一次渲染了30的listem,緩存了兩個節點,所以加載的數據為32個。
日誌輸出結果:
// 父組件使用Repeat渲染列表
@Entry
@Component
struct repeatpage {
@State items: string[] = [];
aboutToAppear() {
// 初始化數據
for (let i = 0; i < 100; i++) {
this.items.push(`列表項 ${i}`);
}
}
build() {
List() {
Repeat(this.items)
// 遍歷每個數組元素
.each((item: RepeatItem<string>) => {
ListItem() {
Text(item.item)
.fontSize(20)
.width('100%')
.textAlign(TextAlign.Center)
}.onAppear(()=>{
// 當listitem渲染的時候調用
console.log('gxxt ',item.item+' 出現了')
})
})// 開啓懶加載
.virtualScroll()
}
.width('100%')
.cachedCount(2) //緩存兩個節點
}
}
repeat設置加載模板
下面案例中給repeat設置通用模板和huang模板和hong模板,根據index設置不同的顯示模板。
// 父組件使用Repeat渲染列表
@Entry
@Component
struct repeatpage {
@State items: string[] = [];
aboutToAppear() {
// 初始化數據
for (let i = 0; i < 100; i++) {
this.items.push(`列表項 ${i}`);
}
}
build() {
List() {
Repeat(this.items)// 遍歷每個數組元素
.each((item: RepeatItem<string>) => {
ListItem() {
Text(item.item)
.fontSize(20)
.width('100%')
.textAlign(TextAlign.Center)
}.onAppear(() => {
// 當listitem渲染的時候調用
console.log('gxxt ', item.item + ' 出現了')
})
})
.template('huang', (item: RepeatItem<string>) => {
ListItem() {
Text(item.item)
.fontSize(20)
.width('100%')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Yellow)
}.onAppear(() => {
// 當listitem渲染的時候調用
console.log('gxxt ', item.item + ' 出現了')
})
})
.template('hong', (item: RepeatItem<string>) => {
ListItem() {
Text(item.item)
.fontSize(20)
.width('100%')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Red)
}.onAppear(() => {
// 當listitem渲染的時候調用
console.log('gxxt ', item.item + ' 出現了')
})
})
.templateId((item: string, index: number) => {
// 下標被3除餘1 加載huang模板 被3除餘2 加載hong模板 其他的加載each的通用模板
if (index % 3 == 1) {
return 'huang'
} else if (index % 3 == 2) {
return 'hong'
} else {
return ''
}
})// 開啓懶加載
.virtualScroll()
}
.width('100%')
.cachedCount(2) //緩存兩個節點
}
}