直接跳到内容

分页父类

介绍

分页父类把列表请求和状态处理封装好了。你只需要关心请求成功时怎么展示列表,加载、错误、空数据、上拉加载都由框架统一处理。

使用流程

  1. ViewModel 继承 BaseNetWorkListViewModel 并实现 requestListData()
  2. 页面使用 BaseNetWorkListView 包住列表内容。
  3. 列表容器用 RefreshLayout 处理下拉刷新和上拉加载。

列表状态

BaseNetWorkListUiState 有四种状态:

  • LOADING:加载中
  • SUCCESS:请求成功
  • ERROR:请求失败
  • EMPTY:空数据

BaseNetWorkListViewModel API

文件位置:core/base/src/main/ets/viewmodel/BaseNetWorkListViewModel.ets

说明:T 为列表项的数据类型,对应仓库返回的业务实体。例如商品列表时,T 就是 Goods

属性

属性说明类型默认值
uiState当前列表请求状态BaseNetWorkListUiStateLOADING
listData列表数据Array<T>[]
isLoading是否正在加载booleanfalse
isEnableSlideUp是否启用上滑加载booleantrue
currentPage当前页码number1
pageSize每页数量number10
showErrorToast是否展示失败提示booleanfalse

方法

方法说明参数返回值
requestListData()子类实现,返回分页请求 Promise-Promise<NetworkResponse<NetworkPageData<T>>>
onRefresh()下拉刷新-void
onLoadMore()上拉加载更多-void
onRefreshDirection(direction)处理下拉或上拉direction: "pull" | "slideUp"void
retryRequest()失败重试-void

BaseNetWorkListView API

文件位置:core/ui/src/main/ets/component/network/BaseNetWorkListView.ets

参数

参数说明类型默认值
uiState当前列表请求状态BaseNetWorkListUiStateLOADING
onRetry失败后的重试回调() => void空函数
loadingBuilder自定义加载视图CustomBuilder
errorBuilder自定义错误视图CustomBuilder
emptyBuilder自定义空数据视图CustomBuilder
content成功状态内容CustomBuilder

RefreshLayout API

文件位置:core/ui/src/main/ets/component/refresh/RefreshLayout.ets

参数

参数说明类型默认值
loading是否处于加载状态booleanfalse
isEnableSlideUp是否启用上滑加载booleantrue
scroller列表/网格使用的 scrollerScrollernew Scroller()
onRefresh下拉或上拉回调(direction: "pull" | "slideUp") => void空函数
content刷新容器内容CustomBuilder必传

使用示例

下面示例基于项目里的网络列表示例,展示 ViewModel 和页面的标准写法。

ViewModel

ts
import { BaseNetWorkListViewModel } from "base";
import { GoodsRepository } from "data";
import { Goods, GoodsSearchRequest, NetworkPageData, NetworkResponse } from "model";

/**
 * @file Network List Demo 示例页 ViewModel
 */
@ObservedV2
export default class NetworkListDemoViewModel extends BaseNetWorkListViewModel<Goods> {
  /**
   * 商品仓库
   */
  private repository: GoodsRepository = new GoodsRepository();

  /**
   * 请求商品分页数据
   * @returns {Promise<NetworkResponse<NetworkPageData<Goods>>>} 网络请求 Promise
   */
  protected requestListData(): Promise<NetworkResponse<NetworkPageData<Goods>>> {
    const request: GoodsSearchRequest = new GoodsSearchRequest();
    request.page = this.currentPage;
    request.size = this.pageSize;
    return this.repository.getGoodsPage(request);
  }
}

页面

ts
import { IBestCard, IBestCell } from "ibestui";
import { P100 } from "designsystem";
import { Goods } from "model";
import { AppNavDestination, BaseNetWorkListView, RefreshLayout } from "ui";
import NetworkListDemoViewModel from "../viewmodel/NetworkListDemoViewModel";

/**
 * @file Network List Demo 示例页视图
 */
@ComponentV2
export struct NetworkListDemoPage {
  /**
   * Network List Demo 示例页 ViewModel
   */
  @Local
  private vm: NetworkListDemoViewModel = new NetworkListDemoViewModel();

  /**
   * 列表滚动控制器
   */
  private listScroller: Scroller = new Scroller();

  /**
   * 构建 Network List Demo 示例页
   * @returns {void} 无返回值
   */
  build() {
    AppNavDestination({
      title: $r("app.string.demo_base_network_list_title"),
      viewModel: this.vm
    }) {
      BaseNetWorkListView({
        uiState: this.vm.uiState,
        onRetry: (): void => this.vm.retryRequest(),
        content: (): void => this.NetworkListDemoContent()
      });
    }
  }

  /**
   * 构建网络列表示例内容
   * @returns {void} 无返回值
   */
  @Builder
  private NetworkListDemoContent() {
    RefreshLayout({
      scroller: this.listScroller,
      loading: this.vm.isLoading,
      isEnableSlideUp: this.vm.isEnableSlideUp,
      onRefresh: (direction): void => this.vm.onRefreshDirection(direction)
    }) {
      List({ space: 12, scroller: this.listScroller }) {
        ForEach(this.vm.listData, (item: Goods) => {
          ListItem() {
            this.NetworkListDemoItem(item);
          }
        }, (item: Goods) => `${item.id}`);
      }
      .padding($r("app.float.space_padding_medium"))
      .width(P100)
      .height(P100);
    }
  }

  /**
   * 渲染列表项
   * @param {Goods} item - 列表项数据
   * @returns {void} 无返回值
   */
  @Builder
  private NetworkListDemoItem(item: Goods) {
    IBestCard({ shadowRadius: 0 }) {
      IBestCell({
        title: item.title,
        label: item.subTitle ?? "",
        isLink: false,
        hasBorder: false,
        leftContentWidth: P100
      });
    }
  }
}

注意事项

  • 页面只关心成功状态如何渲染列表,加载、错误和空数据由 BaseNetWorkListView 处理。
  • 刷新与加载更多统一通过 RefreshLayout 触发,ViewModel 只处理数据与状态。