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

