HarmonyOS鸿蒙Next中swiper组件能不预加载吗
HarmonyOS鸿蒙Next中swiper组件能不预加载吗 通过设置cachedCount为0,不起作用,有办法不让他预加载左右的子组件吗,达到滑到哪才加载哪的效果
设置 cachedCount
为 0
不会禁用预加载。
无法通过设置 cachedCount
或其他配置实现“滑到哪才加载哪”的完全按需加载效果。
Swiper 的设计初衷就是通过预加载来保证流畅体验。
更多关于HarmonyOS鸿蒙Next中swiper组件能不预加载吗的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
swiper的cachedCount是划出去之后会销毁,如果你设置了2,他会缓存起来不让组件销毁而已,跟预加载没关系,我复制官网demo,试了一下打印组件创建生命周期,根本就不会预加载
// xxx.ets
class MyDataSource implements IDataSource {
private list: number[] = [];
constructor(list: number[]) {
this.list = list;
}
totalCount(): number {
return this.list.length;
}
getData(index: number): number {
return this.list[index];
}
registerDataChangeListener(listener: DataChangeListener): void {
}
unregisterDataChangeListener() {
}
}
@Entry
@Component
struct SwiperExample {
private swiperController: SwiperController = new SwiperController();
private data: MyDataSource = new MyDataSource([]);
aboutToAppear(): void {
let list: number[] = [];
for (let i = 1; i <= 10; i++) {
list.push(i);
}
this.data = new MyDataSource(list);
}
build() {
Column({ space: 5 }) {
Swiper(this.swiperController) {
LazyForEach(this.data, (item: string) => {
Text(item.toString())
.width('90%')
.height(160)
.backgroundColor(0xAFEEEE)
.textAlign(TextAlign.Center)
.fontSize(30)
.onAppear(() => {
console.log('appear: ' + item);
})
}, (item: string) => item)
}
.cachedCount(2)
.index(1)
.interval(4000)
.indicator(Indicator.digit() // 设置数字导航点样式
.top(200)
.fontColor(Color.Gray)
.selectedFontColor(Color.Gray)
.digitFont({ size: 20, weight: FontWeight.Bold })
.selectedDigitFont({ size: 20, weight: FontWeight.Normal }))
.loop(true)
.duration(1000)
.itemSpace(0)
.displayArrow(true, false)
Row({ space: 12 }) {
Button('showNext')
.onClick(() => {
this.swiperController.showNext();
})
Button('showPrevious')
.onClick(() => {
this.swiperController.showPrevious();
})
}.margin(5)
}.width('100%')
.margin({ top: 5 })
}
}
-
框架设计限制
Swiper组件默认存在基础缓存机制,即使设置cachedCount(0)
仍会保留至少当前显示项的缓存。多个案例显示,当快速滑动时系统可能无法及时销毁已滑出组件。 -
LazyForEach特性约束
当配合LazyForEach
使用时,系统会根据滑动方向预先创建相邻索引的组件,这与数据源的IDataSource
接口实现机制相关。
通过设置 .cachedCount(0) 无法完全禁用预加载。根据系统实现逻辑,当 cachedCount 设置为 0 或负数时,系统会按照默认值 1 处理,因此始终会预加载至少相邻一个子组件。这是出于基础滑动体验的保障考虑。
你可以尝试使用
动态数据加载控制
结合 onChange 事件手动控制加载时机,实现“滑到哪才加载哪”:
@State currentIndex: number = 0;
Swiper()
.onChange((index: number) => {
this.currentIndex = index;
// 根据index动态加载数据,例如通过接口请求
this.loadDataForIndex(index);
})
【问题分析】
只在LazyForEach和开启了virtualScroll开关的Repeat中生效,生效后超出显示及缓存范围的子节点会被释放。
cacheCount:设置预加载子组件个数,以当前页面为基准,加载当前显示页面的前后个数。前面item删除,后面会向前补位。例如cachedCount=1时,会将当前显示的页面的前面一页和后面一页的子组件都预加载。
【参考代码】
import { BusinessError } from '@kit.BasicServicesKit';
// BasicDataSource实现了IDataSource接口,用于管理listener监听,以及通知LazyForEach数据更新
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [];
private originDataArray: string[] = [];
public totalCount(): number {
return this.originDataArray.length;
}
public getData(index: number): string {
return this.originDataArray[index];
}
// 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener');
this.listeners.push(listener);
}
}
// 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener');
this.listeners.splice(pos, 1);
}
}
// 通知LazyForEach组件需要重载所有子组件
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded();
});
}
// 通知LazyForEach组件需要在index对应索引处添加子组件
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index);
// 写法2:listener.onDatasetChange([{type: DataOperationType.ADD, index: index}]);
});
}
// 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
// 写法2:listener.onDatasetChange([{type: DataOperationType.CHANGE, index: index}]);
});
}
// 通知LazyForEach组件需要在index对应索引处删除该子组件
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
// 写法2:listener.onDatasetChange([{type: DataOperationType.DELETE, index: index}]);
});
}
// 通知LazyForEach组件将from索引和to索引处的子组件进行交换
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to);
// 写法2:listener.onDatasetChange(
// [{type: DataOperationType.EXCHANGE, index: {start: from, end: to}}]);
});
}
notifyDatasetChange(operations: DataOperation[]): void {
this.listeners.forEach(listener => {
listener.onDatasetChange(operations);
});
}
}
class MyDataSource extends BasicDataSource {
private dataArray: string[] = [];
public totalCount(): number {
return this.dataArray.length;
}
public getData(index: number): string {
return this.dataArray[index];
}
public pushData(data: string): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
}
@Entry
@Component
struct PageCacheCount {
@State currentIndex: number = 1;
private swiperController: SwiperController = new SwiperController();
private data: MyDataSource = new MyDataSource();
aboutToAppear() {
for (let i = 0; i <= 20; i++) {
this.data.pushData(`Hello ${i}`);
}
}
build() {
Column() {
Swiper(this.swiperController) {
LazyForEach(this.data, (item: string) => {
ListItem() {
Row() {
MyComponent({ txt: item })
}.margin({ left: 10, right: 10 })
}
}, (item: string) => item)
}
.cachedCount(0)
.width("90%")
.height(200)
}
.width("100%")
.margin(5)
}
}
@Component
struct MyComponent {
private txt: string = "";
aboutToAppear(): void {
console.info('aboutToAppear txt:' + this.txt);
}
build() {
Text(this.txt)
.textAlign(TextAlign.Center)
.width('100%')
.height('100%')
.backgroundColor(0xAFEEEE)
}
}
HarmonyOS鸿蒙Next的Swiper组件默认支持预加载机制。通过设置cachedCount属性可控制预加载数量,设为0即可禁用预加载。该属性在Swiper组件的参数中直接配置,实现方式为:cachedCount(0)
。禁用后相邻页面将不会提前加载和渲染,仅当前页保持活跃状态。此配置适用于需要严格控制内存占用的场景。
在HarmonyOS Next中,Swiper组件的cachedCount
属性目前不支持设置为0来完全禁用预加载。该属性用于控制预加载的页面数量,但最小值为1,无法通过配置实现滑到哪加载哪的效果。
如果希望实现按需加载,可以考虑以下替代方案:
- 结合LazyForEach或条件渲染,在Swiper的每个子项中动态控制内容加载时机。
- 监听Swiper的索引变化事件,在滑动到特定位置时再触发子组件的数据加载或渲染。
需要注意的是,Swiper本身的设计包含预加载机制以保障滑动流畅性,完全禁用可能会影响用户体验。