如何为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
相关产品推荐
相关产品推荐

