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

为Angular Material Paginator添加页码导航功能

解决方案:自定义 mat-paginator 实现带页码导航的分页

核心思路

基于 Angular Material 的 MatPaginator 扩展,通过自定义指令+样式调整,保留原有 pageSizeOptions 功能的同时,添加页码导航控件,满足布局需求。

步骤1:创建自定义分页指令

直接在现有 MatPaginator 基础上注入逻辑,避免完全重写:

import { Directive, OnInit, Host, Self, ElementRef, Renderer2 } from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';

@Directive({
  selector: '[appCustomPaginator]'
})
export class CustomPaginatorDirective implements OnInit {
  private pageContainer!: HTMLElement;

  constructor(
    @Host() @Self() private paginator: MatPaginator,
    private el: ElementRef,
    private renderer: Renderer2
  ) {}

  ngOnInit(): void {
    this.paginator.page.subscribe(() => this.renderPageNumbers());
    this.createPageContainer();
    this.renderPageNumbers();
    this.adjustLayout();
  }

  private createPageContainer(): void {
    // 在分页控件中间插入页码容器
    const paginatorInner = this.el.nativeElement.querySelector('.mat-paginator-inner-container');
    const nextPageBtn = paginatorInner.querySelector('.mat-paginator-navigation-next');
    
    this.pageContainer = this.renderer.createElement('div');
    this.renderer.addClass(this.pageContainer, 'custom-page-numbers');
    this.renderer.insertBefore(paginatorInner, this.pageContainer, nextPageBtn);
  }

  private renderPageNumbers(): void {
    // 清空原有页码
    this.pageContainer.innerHTML = '';
    
    const totalPages = Math.ceil(this.paginator.length / this.paginator.pageSize);
    const currentPage = this.paginator.pageIndex + 1;
    
    // 计算要显示的页码范围(每次展示3个)
    let startPage = Math.max(1, currentPage - 1);
    let endPage = Math.min(totalPages, currentPage + 1);
    
    // 处理边界情况:如果当前页是第一页,显示1-3;最后一页则显示totalPages-2到totalPages
    if (currentPage === 1) endPage = Math.min(3, totalPages);
    if (currentPage === totalPages) startPage = Math.max(1, totalPages - 2);

    // 生成页码按钮
    for (let i = startPage; i <= endPage; i++) {
      const pageBtn = this.renderer.createElement('button');
      this.renderer.addClass(pageBtn, 'custom-page-btn');
      if (i === currentPage) {
        this.renderer.addClass(pageBtn, 'active');
      }
      this.renderer.setProperty(pageBtn, 'textContent', i);
      this.renderer.listen(pageBtn, 'click', () => {
        this.paginator.pageIndex = i - 1;
        this.paginator.page.emit({
          pageIndex: this.paginator.pageIndex,
          pageSize: this.paginator.pageSize,
          length: this.paginator.length
        });
      });
      this.renderer.appendChild(this.pageContainer, pageBtn);
    }
  }

  private adjustLayout(): void {
    // 调整布局:页码和箭头居中,pageSize控件靠右
    const paginatorInner = this.el.nativeElement.querySelector('.mat-paginator-inner-container');
    this.renderer.setStyle(paginatorInner, 'justify-content', 'space-between');
    
    const navigationContainer = paginatorInner.querySelector('.mat-paginator-navigation');
    this.renderer.addClass(navigationContainer, 'custom-navigation-container');
    this.renderer.setStyle(navigationContainer, 'display', 'flex');
    this.renderer.setStyle(navigationContainer, 'align-items', 'center');
    this.renderer.setStyle(navigationContainer, 'gap', '16px');
  }
}

步骤2:添加全局样式(styles.scss)

.custom-page-numbers {
  display: flex;
  gap: 8px;
}

.custom-page-btn {
  min-width: 32px;
  height: 32px;
  border-radius: 4px;
  border: 1px solid rgba(0,0,0,0.12);
  background: white;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;

  &:hover {
    background: rgba(0,0,0,0.04);
  }

  &.active {
    background: #1976d2;
    color: white;
    border-color: #1976d2;
  }
}

.custom-navigation-container {
  justify-content: center;
  flex: 1;
}

.mat-paginator-page-size {
  margin-left: auto;
}

步骤3:在组件中使用

<mat-paginator
  [length]="totalItems"
  [pageSize]="pageSize"
  [pageSizeOptions]="[5, 10, 20]"
  appCustomPaginator
  (page)="onPageChange($event)"
></mat-paginator>

关键说明

  • 保留原有功能:指令完全依赖原生 MatPaginator 的 pageIndex、pageSize、length 等属性,pageSizeOptions 的下拉选择会自动触发 page 事件,指令会重新渲染页码,确保协同工作。
  • 页码范围控制:通过逻辑处理,始终保持显示3个连续页码,自动适配首尾页的边界情况。
  • 布局调整:通过修改 mat-paginator-inner-container 的 justify-content 为 space-between,让页码导航居中,pageSize 控件自动靠右。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 00:01:23