浅入Repeat:子组件复用
·
🎯 V2: 浅入Repeat:子组件复用
⭐⭐⭐⭐⭐
📌 见解
1️⃣ Repeat常在滚动类容器组件内使用,List、ListItemGroup、Grid、Swiper以及WaterFlow组件支持Repeat懒加载场景
2️⃣ Repeat当前不支持动画效果,与@Builder组合使用时候需要将RepeatItem类型整体进行传参,才是双向绑定刷新❗❗❗
3️⃣ Repeat组件默认开启节点复用功能。从API version 18开始,可以自定义配置VirtualScrollOptions,以及缓存自定义组件冻结功能, Repeat拖拽排序特性从API version 19开始支持❗❗❗
4️⃣ Repeat的.key()属性为每个子组件生成一个键值。用于对标记的组件做curd的操作,当.key()缺省时,Repeat会生成新的随机键值
5️⃣ template与templateId主要用于实现动态多模板渲染,严格区分组件复用池,匹配不到时候默认使用each模版
⚠️ 使用场景
| 维度 | Repeat | LazyForEach | ForEach |
|---|---|---|---|
| 数据量 | 大/中数据集 | (需开懒加载)超大数据集 | 小数据集(≤100) |
| 节点复用 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| 懒加载 | ✅ 通过virtualScroll开启 | ✅ 内置支持 | ❌ 不支持 |
| 模板多样性 | ✅ 多模板渲染 | ❌ 单一模板 | ❌ 单一模板 |
| 数据更新监听 | ✅ 自动监听状态变量 | ❌ 需手动实现IDataSource | ✅ 自动监听数组变化 |
| 适用场景 | 动态数据、需复用节点/多模板 | 流式数据、超长列表 | 静态数据、快速交互 |
🧩 拆解
@ObservedV2
class mockViewModel {
@Trace str: string = ''
num: number = 0
}
@Entry
@ComponentV2
struct RepeatCase {
@Local mockList: Array<mockViewModel> = []
@Local mockListLength: number = this.mockList.length
private scroller: Scroller = new Scroller()
private start: number = 1
aboutToAppear(): void {
for (let i = 0; i < 8; i++) {
this.mockList.push({ str: `mock${i}`, num: i })
}
}
build() {
Column({ space: 20 }) {
Text('添加')
.padding(20)
.fontColor(Color.White)
.backgroundColor(Color.Green)
.borderRadius(4)
.onClick(() => {
const addLength = this.mockList.length + 1
this.mockList.push({ str: `mock${addLength}`, num: addLength })
// TODO: 屏幕外的列表数据发生变化时,保证滚动条位置不变
const rect = this.scroller.getItemRect(this.start) // 获取子组件的大小位置
this.scroller.scrollToIndex(this.start + 1) // 滑动到指定index
this.scroller.scrollBy(0, -rect.y) // 滑动指定距离
})
List({ space: 10, scroller: this.scroller }) {
Repeat(this.mockList)
.each((obj: RepeatItem<mockViewModel>) => {
ListItem() {
RepeatItemCase({
item: obj.item, delItem: () => {
this.mockList.splice(obj.index, 1)
}
})
}
})
.key(item => item.str)
.virtualScroll({ totalCount: this.mockList.length }) // 默认加载所有组件
// TODO: API 19+才可使用
// .virtualScroll({
// // 期望的数据源总长度为1000。
// onTotalCount: () => { return 1000; },
// // 实现数据懒加载。
// onLazyLoading: (index: number) => { this.mockList[index] = this.mockList[index]; }
// })
}
.scrollBar(BarState.Off)
.width('100%')
.padding({ bottom: 100 })
.onScrollIndex((start, end) => {
this.start = start
})
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Start)
.padding({ left: 5, right: 5 })
}
}
@ComponentV2
struct RepeatItemCase {
@Require @Param item: mockViewModel
@Event delItem: () => void = () => {}
build() {
Row() {
Text(this.item.str)
Blank()
Text('删除')
.padding(5)
.fontColor(Color.White)
.backgroundColor(Color.Red)
.borderRadius(4)
.onClick(() => {
this.delItem()
this.getUIContext().getPromptAction().showToast({ message: `删除了${this.item.num}项` })
})
}
.width('100%')
.height(100)
.borderWidth(1)
.borderColor(Color.Black)
.borderRadius(10)
.padding({ left: 20, right: 20 })
}
}
📝 Repeat使用方式优于Foreach和LazyForEach,需要注意的是,数据精准懒加载(当数据源总长度较长,或数据项加载耗时较长时,动态加载长列表数据,例如:用户滑动到列表第500项时,触发加载该位置的数据。)需要在api19+才能使用
🌸🌼🌺
更多推荐



所有评论(0)