优秀的编程知识分享平台

网站首页 > 技术文章 正文

鸿蒙开发中LazyForEach的使用(鸿蒙开发视频教程)

nanyue 2024-08-05 20:10:00 技术文章 5 ℃

鸿蒙提供了两种列表渲染模式,一种是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 }
最近发表
标签列表