鸿蒙提供了两种列表渲染模式,一种是ForEach,另外一种是LazyForEach-官方文档
LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。
LazyForEach的使用特别像之前前端领域里的一个叫做虚拟列表的概念, 不论你有100条还是100000条记录,当前始终只渲染可视区域的内容,也就是5条,10条,只不过原来我们需要借助不同的虚拟列表组件或者自己去实现,这里面我们直接使用LazyForEach就可以了,但是同样的,使用LazyForEach遍历的数据源必须继承实现IDataSource这个接口
也就是我们的数据源不能再使用原始的数组对象,数据源必须实现IDataSource里面的几个方法
- 下面是使用限制
在models下新建一个base_datasource.ets
export class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [];
public totalCount(): number {
return 0;
}
public getData(index: number): object | null {
return null ;
}
// 该方法为框架侧调用,为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);
})
}
// 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
})
}
// 通知LazyForEach组件需要在index对应索引处删除该子组件
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
})
}
}
export class ListDataSource extends BasicDataSource {
private dataArray: object[] = [];
public totalCount(): number {
return this.dataArray.length;
}
public getData(index: number): object {
return this.dataArray[index];
}
public addData(index: number, data: object): void {
this.dataArray.splice(index, 0, data);
this.notifyDataAdd(index);
}
public pushData(data: object): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
public reloadData (list: object[]) {
this.dataArray = list
this.notifyDataReload() // 重新加载
}
}
- 在models/index.ets统一导出
export * from './base_datasource'
- 在HmList中实现
import { HmLoading } from './HmLoading'
import { ListDataSource } from '../models'
@Component
struct HmList {
@State
refreshIng: boolean = false // 控制下拉刷新
@State
loading: boolean = false // 控制上拉加载
@Prop
finished: boolean // 是否结束
@Link
@Watch("updateDataSource")
dataSource: object[] // 数据源
@BuilderParam
renderItem: (item: object) => void
onLoad: () => void = () => {
} // 上拉加载函数
onRefresh: () => void = () => {
} // 下拉刷新函数
loadingText: string = "加载数据中" // 加载中文本
finishText: string = "没有内容啦" // 结束文本
showLoadingIcon: boolean = true // 是否显示加载进度
lazyDataSource: ListDataSource = new ListDataSource()
// 更新数据
updateDataSource() {
this.lazyDataSource.reloadData(this.dataSource)
}
// 获取底部显示的文本
@Builder
getBottomDisplay() {
Row({ space: 10 }) {
if (this.finished) {
Text(this.finishText)
.fontSize(14)
.fontColor($r("app.color.text_secondary"))
} else {
if (this.loading) {
Text(this.loadingText)
.fontSize(14)
.fontColor($r("app.color.text_secondary"))
if(this.showLoadingIcon) {
HmLoading({
hWidth: 20
})
}
}
}
}
.height(50)
.width('100%')
.justifyContent(FlexAlign.Center)
}
build() {
Refresh({ refreshing: $this.refreshIng }) {
List() {
LazyForEach(this.lazyDataSource, (item: object) => {
ListItem() {
if (this.renderItem) {
this.renderItem(item)
}
}.width('100%')
})
ListItem() {
this.getBottomDisplay()
}
}
.onReachEnd(async () => {
if (!this.finished && !this.loading) {
this.loading = true
await this.onLoad()
this.loading = false
}
})
}
.onStateChange(async value => {
if (value === RefreshStatus.Refresh) {
await this.onRefresh()
this.refreshIng = false
this.loading = false
}
})
}
}
export { HmList }