HarmonyOS 鸿蒙Next中List组件实现下拉刷新和上拉加载更多

HarmonyOS 鸿蒙Next中List组件实现下拉刷新和上拉加载更多 需要实现案例列表的分页加载,支持下拉刷新和滚动到底部自动加载更多。

3 回复

原理解析

  • Refresh组件:包裹List实现下拉刷新
  • onReachEnd事件:List滚动到底部时触发
  • 分页参数:维护当前页码和是否还有更多数据

解决方案

interface CaseListItem {
  caseId: string;
  title: string;
  phenomenon: string;
  tags: string[];
}

@Entry
@Component
struct CaseListPage {
  @State caseList: CaseListItem[] = [];
  @State isLoading: boolean = false;
  @State isRefreshing: boolean = false;
  @State hasMore: boolean = true;
  @State currentPage: number = 1;
  private pageSize: number = 20;
  
  aboutToAppear(): void {
    this.loadData(true);
  }
  
  async loadData(isRefresh: boolean = false): Promise<void> {
    if (this.isLoading) return;
    
    if (isRefresh) {
      this.currentPage = 1;
      this.hasMore = true;
    }
    
    if (!this.hasMore && !isRefresh) return;
    
    this.isLoading = true;
    
    try {
      // 模拟API请求
      const result = await this.fetchCases(this.currentPage, this.pageSize);
      
      if (isRefresh) {
        this.caseList = result.list;
      } else {
        this.caseList = [...this.caseList, ...result.list];
      }
      
      this.hasMore = result.list.length >= this.pageSize;
      if (this.hasMore) {
        this.currentPage++;
      }
    } catch (e) {
      console.error('加载失败', e);
    } finally {
      this.isLoading = false;
      this.isRefreshing = false;
    }
  }
  
  async fetchCases(page: number, size: number): Promise<{ list: CaseListItem[] }> {
    // 实际项目中调用数据库或API
    const allCases = await caseDao.getList();
    const start = (page - 1) * size;
    const end = start + size;
    return { list: allCases.slice(start, end) };
  }
  
  build() {
    Column() {
      // 顶部导航栏
      Row() {
        Text('案例库')
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
        Blank()
        Text(`共 ${this.caseList.length} 条`)
          .fontSize(13)
          .fontColor('#999999')
      }
      .width('100%')
      .height(56)
      .padding({ left: 16, right: 16 })
      
      // 下拉刷新 + 列表
      Refresh({ refreshing: $$this.isRefreshing }) {
        List() {
          ForEach(this.caseList, (item: CaseListItem) => {
            ListItem() {
              this.CaseCard(item)
            }
            .padding({ left: 16, right: 16, bottom: 12 })
          }, (item: CaseListItem) => item.caseId)
          
          // 底部加载状态
          ListItem() {
            this.LoadMoreFooter()
          }
        }
        .width('100%')
        .layoutWeight(1)
        .divider({ strokeWidth: 0 })
        .onReachEnd(() => {
          // 滚动到底部,加载更多
          if (!this.isLoading && this.hasMore) {
            this.loadData(false);
          }
        })
      }
      .onRefreshing(() => {
        // 下拉刷新
        this.loadData(true);
      })
    }
    .width('100%')
    .height('100%')
  }
  
  @Builder
  CaseCard(item: CaseListItem) {
    Column({ space: 8 }) {
      Text(item.title)
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
        .maxLines(2)
        .textOverflow({ overflow: TextOverflow.Ellipsis })
      
      Text(item.phenomenon)
        .fontSize(13)
        .fontColor('#666666')
        .maxLines(2)
        .textOverflow({ overflow: TextOverflow.Ellipsis })
      
      Row({ space: 6 }) {
        ForEach(item.tags.slice(0, 3), (tag: string) => {
          Text(tag)
            .fontSize(11)
            .fontColor('#1890FF')
            .backgroundColor('#E6F7FF')
            .padding({ left: 8, right: 8, top: 3, bottom: 3 })
            .borderRadius(4)
        })
      }
    }
    .width('100%')
    .padding(16)
    .backgroundColor(Color.White)
    .borderRadius(12)
    .alignItems(HorizontalAlign.Start)
  }
  
  @Builder
  LoadMoreFooter() {
    Row() {
      if (this.isLoading) {
        LoadingProgress().width(20).height(20)
        Text('加载中...').fontSize(13).fontColor('#999999').margin({ left: 8 })
      } else if (!this.hasMore) {
        Text('— 没有更多了 —').fontSize(13).fontColor('#CCCCCC')
      }
    }
    .width('100%')
    .height(50)
    .justifyContent(FlexAlign.Center)
  }
}

更多关于HarmonyOS 鸿蒙Next中List组件实现下拉刷新和上拉加载更多的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,List组件通过refreshloadMore事件实现下拉刷新和上拉加载。使用ListonScrollIndex监听滚动位置触发加载更多。下拉刷新通常结合Refresh组件,通过onRefresh回调更新数据。上拉加载在列表滚动到底部时触发,更新数据源并重新渲染列表。

在HarmonyOS Next中,可以使用List组件配合RefreshListonReachEnd事件来实现下拉刷新与上拉加载更多。以下是核心实现方案:

1. 下拉刷新

使用Refresh组件包裹List,通过onRefresh回调触发数据刷新。

Refresh({
  refreshing: this.isRefreshing, // 控制刷新状态
  onRefresh: () => {
    this.isRefreshing = true;
    // 执行刷新逻辑,如重新请求第一页数据
    this.loadData(true);
  }
}) {
  List() {
    // 列表内容
  }
}

2. 上拉加载更多

监听ListonReachEnd事件,触发时加载下一页数据。

List() {
  // 列表项
}
.onReachEnd(() => {
  if (!this.isLoading && this.hasMore) {
    this.isLoading = true;
    // 执行加载更多逻辑
    this.loadData(false);
  }
})

3. 状态管理

需要维护的关键状态:

  • isRefreshing: 控制刷新动画
  • isLoading: 防止重复加载
  • hasMore: 是否还有更多数据
  • pageIndex: 当前页码

4. 数据加载函数示例

async loadData(isRefresh: boolean) {
  if (isRefresh) {
    this.pageIndex = 1;
  } else {
    this.pageIndex += 1;
  }
  
  try {
    const newData = await this.fetchData(this.pageIndex);
    if (isRefresh) {
      this.data = newData;
    } else {
      this.data = this.data.concat(newData);
    }
    this.hasMore = newData.length >= PAGE_SIZE;
  } catch (error) {
    // 错误处理
  } finally {
    this.isRefreshing = false;
    this.isLoading = false;
  }
}

5. 完整组件结构

struct ListWithRefresh {
  @State data: Item[] = [];
  @State isRefreshing: boolean = false;
  @State isLoading: boolean = false;
  @State hasMore: boolean = true;
  private pageIndex: number = 1;

  build() {
    Column() {
      Refresh({
        refreshing: this.isRefreshing,
        onRefresh: () => {
          this.isRefreshing = true;
          this.loadData(true);
        }
      }) {
        List() {
          ForEach(this.data, (item: Item) => {
            ListItem() {
              // 列表项UI
            }
          })
        }
        .onReachEnd(() => {
          if (!this.isLoading && this.hasMore) {
            this.isLoading = true;
            this.loadData(false);
          }
        })
      }
    }
  }
}

注意事项

  • 确保在数据加载完成后更新isRefreshingisLoading状态
  • 可根据需求添加加载中和无更多数据的UI提示
  • 网络请求失败时需要正确处理状态重置

这种实现方式符合HarmonyOS Next的声明式UI范式,能流畅处理分页加载场景。

回到顶部