鸿蒙开发深入浅出03(封装通用LazyForEach实现懒加载)
- 1、效果展示
- 2、ets/models/BasicDataSource.ets
- 3、ets/models/HomeData.ets
- 4、ets/api/home.ets
- 5、ets/pages/Home.ets
- 6、ets/views/Home/SwiperLayout.ets
- 7、后端代码
1、效果展示
2、ets/models/BasicDataSource.ets
// BasicDataSource实现了IDataSource接口,用于管理listener监听,以及通知LazyForEach数据更新
// https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-rendering-control-lazyforeach-V5#stringdata%E7%B1%BB%E5%9E%8B%E6%95%B0%E7%BB%84%E7%9A%84basicdatasource%E4%BB%A3%E7%A0%81
export default class BasicDataSource<T> implements IDataSource {
// 内部用来触发UI更新的对象
private listeners: DataChangeListener[] = [];
// 管理的数据
private list: T[] = [];
// 返回数据总长度
public totalCount(): number {
return this.list.length;
}
// 读取对应下标的数据
public getData(index: number): T {
return this.list[index];
}
// 保存单个数据
public setData(item: T) {
// 只会更新数据,不会更新UI
this.list.push(item);
// 更新UI操作
this.notifyDataAdd(this.list.length - 1);
}
// 更新所有列表数据
public setList(list: T[]) {
this.list = list;
// 全部通知修改
this.notifyDataReload();
}
// 该方法为框架侧调用,为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);
})
}
}
3、ets/models/HomeData.ets
注意因为我们这个模块使用了BasicDataSource.ets,所以从鸿蒙开发深入浅出02(封装Axios请求、渲染Swiper)需改为ets后缀。
import BasicDataSource from './BasicDataSource';
@Observed
export class BasicListDataSource<T> extends BasicDataSource<T> {
lists: T[] = [];
}
export interface IHomeData {
"bannerList": IBannerList
"navList": INavList
"tileList": ITileList
"planList": IPlanList
"adPicture": string
}
// 计划列表类型
export interface IPlanItem {
"id": number
"imageURL": string
}
export type IPlanList = IPlanItem[]
// 瓷片列表类型
export interface ITileItem {
"id": number
"imageURL": string
"title": string
"sub_title": string
}
export type ITileList = ITileItem[]
// 导航列表类型
export interface INavItem {
"id": number
"title": string
"imageURL": string
}
export type INavList = INavItem[]
// 轮播图类型
export interface IBannerItem {
"id": number
"name": string
"imageURL": string
}
export type IBannerList = IBannerItem[]
4、ets/api/home.ets
同 3 所述,home.ts 也需改为 ets 结尾,并添加返回类型。
import { http } from '../utils/http'
import type { IHomeData } from '../models/HomeData'
// 获取页面数据
export const getHomeDataApi = (): Promise<IHomeData> => {
return http.get<IHomeData>('/home/info')
}
5、ets/pages/Home.ets
import { getHomeDataApi } from "../api/home"
import { BasicListDataSource, IBannerItem, IBannerList } from "../models/HomeData"
import SwiperLayout from '../views/Home/SwiperLayout'
/**
* MyHouseApplication #项目的名称
* Home.ets #文件名称
* Created by zhong ON 2025/2/23 #作者及添加日期
*/
@Component
export default struct Home {
@State bannerList: BasicListDataSource<IBannerItem> = new BasicListDataSource();
// 获取首页数据的函数
getHomeData = async () => {
const result = await getHomeDataApi();
this.bannerList.setList(result.bannerList);
}
// 生命周期函数,初始化页面时触发
aboutToAppear(): void {
this.getHomeData();
}
build() {
Scroll() {
Column() {
SwiperLayout({ bannerList: this.bannerList });
}.width('100%')
}
.width('100%')
.height('100%')
.scrollBar(BarState.Off)
.align(Alignment.TopStart)
}
}
6、ets/views/Home/SwiperLayout.ets
/**
* MyHouseApplication #项目的名称
* SwiperLayout.ets #文件名称
* Created by zhong ON 2025/2/23 #作者及添加日期
*/
import { IBannerItem, BasicListDataSource } from "../../models/HomeData"
@Component
export default struct SwiperLayout {
@ObjectLink bannerList: BasicListDataSource<IBannerItem>;
build() {
Swiper() {
LazyForEach(this.bannerList, (banner: IBannerItem) => {
Image(banner.imageURL).width('100%')
.height('100%')
.objectFit(ImageFit.Fill)
}, (banner: IBannerItem) => banner.id + '')
}.width('100%')
.height(211 - 36)
.indicator(
new DotIndicator()
.color($r('app.color.indicator_color'))
.selectedColor($r('app.color.indicator_active_color'))
)
}
}
7、后端代码
双击 zufangBackend-windows-amd64.exe 运行