1. 懒加载:LazyForEach
替代 ForEach
原理:只渲染可视区域内的页面,滑出后自动销毁。
// 优化前:ForEach一次性加载所有页面(内存爆炸!)
Swiper() {
ForEach(this.list, (item: number) => {
SwiperItem().height('100%') // 1000个页面全加载
})
}
// 优化后:LazyForEach按需加载
Swiper() {
LazyForEach(this.dataSource, (item: Question) => {
QuestionSwiperItem({ itemData: item }) // 仅渲染可见页
})
}
效果(1000页场景):
加载方式 | 耗时 | 丢帧率 | 内存占用 |
---|---|---|---|
ForEach | 951ms | 8.5% | 200MB |
LazyForEach | 280ms | 0% | 25MB |
💡 关键点:数据源需实现IDataSource
接口(详见官方示例)。
2. 缓存控制:cachedCount
精准调优
原理:预加载屏幕外页面,但缓存过多会爆内存!
Swiper() {
LazyForEach(...)
}
.cachedCount(2) // 核心参数:缓存左右各2页
性能对比(20页图库场景):
缓存数量 | 丢帧率 | 内存占用 |
---|---|---|
1 | 3.0% | 64MB |
2 | 3.3% | 117MB |
8 | 3.0% | 377MB |
✅ 结论:一屏一页时,cachedCount=1或2
最佳,内存与流畅度兼顾!
3. 抛滑预加载:onAnimationStart
抢跑资源
原理:用户松手抛滑瞬间,主线程空闲时提前加载后续资源。
Swiper()
.cachedCount(1)
.onAnimationStart((index, targetIndex) => { // 抛滑开始回调
// 提前加载目标页的图片/网络数据
if (targetIndex < data.length - 2) {
loadImageAsync(targetIndex + 2); // 提前加载后面第2页
}
})
子组件优化:检查资源是否已预加载
@Component
struct PreloadSwiperItem {
aboutToAppear() {
if (!this.data.pixelMap) { // 无缓存才下载
downloadImage().then(pixelMap => {
this.data.pixelMap = pixelMap;
})
}
}
}
效果:
- 未预加载:组件构建耗时 50ms
- 预加载后:构建耗时 2ms(资源已就绪)
4. 组件复用:@Reusable
减少创建开销
原理:复用滑出屏幕的组件实例,减少频繁创建/销毁。
@Reusable // 关键装饰器!
@Component
struct QuestionSwiperItem {
aboutToReuse(params: Object) { // 复用时的数据更新
this.itemData = params.itemData as Question;
}
build() { ... }
}
📌 官方数据:复用后相同场景下,帧率提升 15%+ ,内存波动减少。
三、总结:Swiper优化四板斧
- 懒加载必用:
LazyForEach
替代ForEach
- 缓存精细化:
cachedCount
推荐值 1~2 - 抛滑抢资源:
onAnimationStart
+ 异步预加载 - 组件要复用:
@Reusable
+aboutToReuse()
更新数据
最后的话
这次挖到的鸿蒙性能优化案例确实让人眼前一亮!实际接入后,我们的图库页帧率从45fps→58fps,效果拔群。大家遇到复杂列表/轮播场景时,一定要试试这些方案。如果有其他坑或经验,欢迎在评论区交流呀 👇
觉得有用记得点赞收藏! 🚀