Skip to content

通用组件

概述

通用组件模块提供了一系列可复用的 UI 组件,用于简化页面开发。

组件列表

组件职责使用场景
Empty空状态组件数据为空时显示
EmptyData数据为空列表无数据
EmptyError错误状态请求失败
EmptyNetwork网络错误网络异常
Loading加载指示器数据加载中
PageLoading页面加载整页加载
AppNavDestination页面导航容器,统一生命周期转发与标题栏配置页面导航
BaseNetWorkView单次请求状态视图(加载/错误/成功)网络请求页面
BaseNetWorkListView列表请求状态视图(加载/错误/空/成功)列表页面
RefreshLayout下拉刷新与上拉加载容器下拉刷新/上滑加载

空状态组件

Empty

通用空状态组件:

typescript
import { Empty } from "@core/components";

Empty({
  image: $r("app.media.empty"),
  title: "暂无数据",
  description: "当前没有任何内容"
});

EmptyData

数据为空组件:

typescript
import { EmptyData } from "@core/components";

EmptyData({
  onRetry: () => {
    // 重试逻辑
  }
});

EmptyError

错误状态组件:

typescript
import { EmptyError } from "@core/components";

EmptyError({
  message: "加载失败",
  onRetry: () => {
    // 重试逻辑
  }
});

EmptyNetwork

网络错误组件:

typescript
import { EmptyNetwork } from "@core/components";

EmptyNetwork({
  onRetry: () => {
    // 重试逻辑
  }
});

加载组件

Loading

加载指示器:

typescript
import { Loading } from "@core/components";

Loading();

PageLoading

页面加载组件:

typescript
import { PageLoading } from "@core/components";

PageLoading({
  message: "加载中..."
});

网络请求视图

BaseNetWorkView

配合 BaseNetWorkViewModel 使用的视图组件:

typescript
import { BaseNetWorkView } from "@core/components";
import { BaseNetWorkViewModel } from "@core/base";

@Entry
@Component
struct MyPage {
  @Local viewModel: MyViewModel = new MyViewModel();

  build() {
    BaseNetWorkView({
      viewModel: this.viewModel,
      contentBuilder: () => {
        // 成功状态的内容
        this.buildContent();
      }
    });
  }

  @Builder
  buildContent() {
    Column() {
      Text(this.viewModel.data?.name);
    }
  }
}

BaseNetWorkListView

配合 BaseNetWorkListViewModel 使用的列表视图组件:

typescript
import { BaseNetWorkListView } from "@core/components";
import { BaseNetWorkListViewModel } from "@core/base";

@Entry
@Component
struct MyListPage {
  @Local viewModel: MyListViewModel = new MyListViewModel();

  build() {
    BaseNetWorkListView({
      viewModel: this.viewModel,
      itemBuilder: (item: MyItem) => {
        // 列表项内容
        this.buildItem(item);
      }
    });
  }

  @Builder
  buildItem(item: MyItem) {
    ListItem() {
      Text(item.name);
    }
  }
}

导航组件

AppNavDestination

导航目标组件,用于页面导航:

typescript
import { AppNavDestination } from "@core/components";

@Entry
@Component
struct MyPage {
  build() {
    AppNavDestination({
      title: "页面标题",
      content: () => {
        this.buildContent();
      }
    });
  }

  @Builder
  buildContent() {
    Column() {
      // 页面内容
    }
  }
}

刷新组件

RefreshLayout

下拉刷新和上滑加载组件,基于 IBestPullRefresh 封装:

参数说明

参数类型默认值说明
loadingbooleanfalse是否处于加载状态
isEnableSlideUpbooleantrue是否启用上滑加载
scrollerScrollernew Scroller()列表/网格使用的 scroller
onRefresh(direction: "pull" | "slideUp") => void() => {}刷新回调
contentCustomBuilder必填刷新容器内容

使用示例

typescript
import { RefreshLayout } from "@core/components";

@Entry
@Component
struct MyListPage {
  @State loading: boolean = false;
  scroller: Scroller = new Scroller();

  build() {
    RefreshLayout({
      loading: this.loading,
      scroller: this.scroller,
      isEnableSlideUp: true,
      onRefresh: (direction: "pull" | "slideUp") => {
        this.handleRefresh(direction);
      },
      content: () => {
        this.buildList();
      }
    });
  }

  @Builder
  buildList() {
    List({ scroller: this.scroller }) {
      ForEach(this.dataList, (item: DataItem) => {
        ListItem() {
          Text(item.name);
        }
      });
    }
  }

  handleRefresh(direction: "pull" | "slideUp") {
    this.loading = true;
    if (direction === "pull") {
      // 下拉刷新逻辑
      this.loadData(1);
    } else {
      // 上滑加载更多逻辑
      this.loadMore();
    }
  }

  async loadData(page: number) {
    // 加载数据
    setTimeout(() => {
      this.loading = false;
    }, 1000);
  }

  async loadMore() {
    // 加载更多数据
    setTimeout(() => {
      this.loading = false;
    }, 1000);
  }
}

使用示例

完整的网络请求页面

typescript
import { BaseNetWorkView } from "@core/components";
import { BaseNetWorkViewModel } from "@core/base";

@ObservedV2
class MyViewModel extends BaseNetWorkViewModel<UserInfo> {
  protected requestRepository(): Promise<NetworkResult<UserInfo>> {
    return this.userService.getUserInfo();
  }
}

@Entry
@Component
struct UserProfilePage {
  @Local viewModel: MyViewModel = new MyViewModel();

  build() {
    BaseNetWorkView({
      viewModel: this.viewModel,
      contentBuilder: () => {
        this.buildContent();
      }
    });
  }

  @Builder
  buildContent() {
    Column() {
      Text(this.viewModel.data?.name);
      Text(this.viewModel.data?.email);
    }
  }
}

完整的列表页面

typescript
import { BaseNetWorkListView } from "@core/components";
import { BaseNetWorkListViewModel } from "@core/base";

@ObservedV2
class MyListViewModel extends BaseNetWorkListViewModel<Product> {
  protected requestRepository(page: number, pageSize: number):
    Promise<NetworkResult<PageData<Product>>> {
    return this.productService.getProductList(page, pageSize);
  }
}

@Entry
@Component
struct ProductListPage {
  @Local viewModel: MyListViewModel = new MyListViewModel();

  build() {
    BaseNetWorkListView({
      viewModel: this.viewModel,
      itemBuilder: (item: Product) => {
        this.buildItem(item);
      }
    });
  }

  @Builder
  buildItem(item: Product) {
    ListItem() {
      Row() {
        Text(item.name);
        Text(`¥${item.price}`);
      }
    }
  }
}

最佳实践

1. 使用封装组件

优先使用封装好的组件,而不是自己实现:

typescript
// 推荐
import { BaseNetWorkView } from "@core/components";

BaseNetWorkView({
  viewModel: this.viewModel,
  contentBuilder: () => this.buildContent()
});

// 不推荐
if (this.viewModel.uiState === BaseNetWorkUiState.LOADING) {
  Loading();
} else if (this.viewModel.uiState === BaseNetWorkUiState.ERROR) {
  EmptyError();
} else {
  this.buildContent();
}

2. 自定义空状态

可以自定义空状态的样式和内容:

typescript
EmptyData({
  image: $r("app.media.custom_empty"),
  title: "自定义标题",
  description: "自定义描述",
  onRetry: () => {
    // 重试逻辑
  }
});

3. 组合使用

可以组合使用多个组件:

typescript
Column() {
  AppNavDestination({
    title: "页面标题",
    content: () => {
      BaseNetWorkView({
        viewModel: this.viewModel,
        contentBuilder: () => this.buildContent()
      });
    }
  });
}

注意事项

  1. 状态管理:确保 ViewModel 正确管理状态
  2. 性能优化:合理使用组件,避免过度渲染
  3. 用户体验:提供友好的错误提示和重试机制

下一步