You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Observable数据实现自定义分页并保留分页状态?

问题原因

每次features$发出新值时,*ngIf包裹的整个区块会被重新渲染,app-pagination组件会被销毁后重新创建,导致之前的分页状态(如当前页码)丢失。


解决方案

方案1:将分页状态提升到父组件维护

把分页的核心状态(当前页码、每页条数等)放到父组件中,通过输入属性传递给app-pagination,组件内部操作分页时通过输出事件通知父组件更新状态。这样即使分页组件被重建,也能从父组件拿到之前的状态。

父组件代码

// 父组件维护分页状态
currentPage = 1;
pageSize = 10;

// 接收分页组件的页码变更事件
onPageChange(page: number) {
  this.currentPage = page;
}

// 计算总条目数(根据你的数据结构调整)
getTotalItems(layers: Record<number, any[]>): number {
  return Object.values(layers).reduce((total, arr) => total + arr.length, 0);
}

模板修改

<ng-container *ngIf="features$ | async as data; else nodata">
   <ng-container *ngFor="let item of data.layers"></ng-container>
    <app-pagination 
      [currentPage]="currentPage"
      [pageSize]="pageSize"
      [totalItems]="getTotalItems(data.layers)"
      (pageChange)="onPageChange($event)"
    ></app-pagination>
</ng-container>

<ng-template #nodata>
  <!-- 空状态内容 -->
</ng-template>

分页组件核心代码

import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'app-pagination',
  templateUrl: './pagination.component.html',
  // 开启OnPush提升性能(可选)
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PaginationComponent {
  @Input() currentPage!: number;
  @Input() pageSize!: number;
  @Input() totalItems!: number;
  @Output() pageChange = new EventEmitter<number>();

  // 点击页码时触发事件
  goToPage(page: number) {
    this.pageChange.emit(page);
  }
}

方案2:缩小渲染范围,分离分页组件

将app-pagination从*ngIf的区块中移出,单独通过async管道获取分页所需的元数据,避免分页组件随列表渲染被频繁重建。

模板修改

<!-- 列表部分受数据状态控制 -->
<ng-container *ngIf="features$ | async as data; else nodata">
   <ng-container *ngFor="let item of data.layers"></ng-container>
</ng-container>

<!-- 分页组件独立渲染,单独获取总条数 -->
<app-pagination 
  [totalItems]="(features$ | async)?.layers | totalItems"
  (pageChange)="onPageChange($event)"
  [currentPage]="currentPage"
></app-pagination>

<ng-template #nodata>
  <!-- 空状态内容 -->
</ng-template>

自定义管道计算总条数

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'totalItems'})
export class TotalItemsPipe implements PipeTransform {
  transform(layers: Record<number, any[]>): number {
    return layers ? Object.values(layers).reduce((total, arr) => total + arr.length, 0) : 0;
  }
}

方案3:优化Observable更新方式(减少不必要渲染)

你当前直接修改原对象再next的方式不符合不可变数据原则,可能导致变更检测异常。应创建新对象触发正确变更,同时配合trackBy减少列表渲染次数(需结合方案1保存分页状态)。

父组件更新数据代码修改

// 创建新对象,避免修改原引用
const currentData = this.features$.getValue();
const newLayers = {
  ...currentData.layers,
  4: [...currentData.layers[4], "new"] // 拷贝数组后添加新元素
};
this.features$.next({...currentData, layers: newLayers});

模板添加trackBy

<ng-container *ngFor="let item of data.layers; trackBy: trackByLayerKey">
</ng-container>

父组件添加trackBy方法

trackByLayerKey(index: number, [key]: [string, any[]]) {
  return key; // 以layers的键作为唯一标识
}

内容的提问来源于stack exchange,提问作者Araviz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 19:07:37