前端实现仿谷歌无总页数分页查询组件

本文讨论了一个项目中遇到的大量数据查询导致服务器超时的问题,提出了两种解决方案。首先尝试了假分页查询,但用户体验不佳。然后采用谷歌分页策略,不显示总页数,只展示关键页码,通过动态调整分页列表来优化用户体验。核心代码展示了如何在Angular7+Antd环境中实现这一策略,确保在无法进行数据库优化的情况下提供流畅的分页体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

项目中的审核系统每天都有至少十几万条数据需要审核,因此列表的分页会有几万页,虽说数据还可以但是server端数据库这些年一直没有升级优化,因此大数据量查询server数据库压力太大导致线上经常报502超时或者500错误;而这个问题就出现在获取列表总条数上面。

解决思路(内部系统)
  • 开始为了快速解决这个问题我们做了假分页查询,也就是server返回假的总条数(就是后端写死的一个值),报错的问题解决了,但是这样做对用户太不友好了。
  • 这个问题最好是做数据库优化,但是由于种种原因暂时还做不了;所以第二种思路就是决定仿照谷歌分页,它不需要展示总页数,只要做好极值处理对用户还是很友好的(依然是返回假条数,只是改变的交互);
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
具体方法
  • 分析谷歌或者百度分页会有一个分页前五后四的概念,有很多种实现方式,但是原理都是一样的。
  • 技术栈:Angular7+ Antd(任何技术栈都可以)
  • 相关组件代码
// html部分
<div *ngIf="pagelist.length > 0">
  <ul class="ant-pagination">
  // 左侧箭头(不重要)
    <li [ngClass]="pagelist[0].val === 1 ? 'ant-pagination-prev ant-pagination-disabled' : 'ant-pagination-prev'" (click)="changePage(curPage - 1)" title="上一页">
      <a class="ant-pagination-item-link">
        <i nz-icon="" type="left" class="anticon anticon-left" ng-reflect-type="left"></i>
      </a>
    </li>
    // 最重要的分页列表pagelist部分
    <li
      [ngClass]="curPage === item.val ? 'ant-pagination-item ant-pagination-item-active' : 'ant-pagination-item'"
      *ngFor="let item of pagelist"
      [title]="item.text"
      (click)="changePage(item.val)"
    >
      {{ item.val }}
    </li>
    // 右侧箭头(不重要)
    <li [ngClass]="pagelist[pagelist.length - 1].val === totalPage ? 'ant-pagination-next ant-pagination-disabled' : 'ant-pagination-prev'" (click)="changePage(curPage + 1)">
      <a class="ant-pagination-item-link ng-star-inserted">
        <i nz-icon="" type="right" class="anticon anticon-right" ng-reflect-type="right"></i>
      </a>
    </li>
  </ul>
</div>
  // 最核心的部分
  /**
   * @description: 获取展示页码list
   * @param {totalPage} 总页数
   * @param {pageGroup} 分页页码条数 这是是10
   * @param {curPage} 当前页
   * @return {pagelist[]} // 除了左右箭头中间循环的页码数组
   */
  getPagelist() {
    let list = []
    let count = Math.floor(this.pageGroup / 2)
    let left = 1 
    let right = this.totalPage
    
    if (this.totalPage > this.pageGroup) {
      if (this.curPage > count + 1) {
        if (this.curPage < this.totalPage - count) {
          left = this.curPage - count
          right = this.curPage + count - 1
        } else {
          // 左右数值固定
          left = this.totalPage - this.pageGroup + 1
        }
      } else {
        right = this.pageGroup
      }
    }
    // 遍历添加到数组里
    while (left <= right) {
      list.push({
        text: left,
        val: left
      })
      left++
    }
    return list
    // [{text:1,val:1},{text:2,val:2},{text:3,val:3},{text:4,val:4},{text:5,val:5},{text:6,val:6},{text:7,val:7},{text:8,val:8},{text:9,val:9},{text:10,val:10}] 
   // [{text:2,val:2},{text:3,val:3},{text:4,val:4},{text:5,val:5},{text:6,val:6},{text:7,val:7},{text:8,val:8},{text:9,val:9},{text:10,val:10},{text:11,val:11}] 
  }
/**
   * @description: 切换页码
   * @param {*} page 当前页码
   * @return {*}
   */
  changePage(page) {
    if (page !== this.curPage && page > 0 && page <= this.totalPage) {
      this.curPage = page
      this.pagelist = this.getPagelist()
      this.pageChange.emit({ index: this.curPage })  // 触发父组件的翻页方法
    }
  }
  @Input() limit: number = 20 // 每页展示的数据
  @Input() total: number = 10000 // 总条数(这个数是虚拟的)
  @Input() newTotal: number = 0 // 不足total返回的新总数
  @Input() curPage: number = 1 // 当前页
  @Input() pageGroup: number = 10 // 分页条数展示10页
  @Input() pageStatus: boolean = false // 当数据不为20或者为空
  @Input() clickStatus: boolean = false // 是否触发了查询按钮
  @Output() pageChange: EventEmitter<object> = new EventEmitter()

  pagelist: any = [] // 循环页码部分
  totalPage: number // 根据总条数计算出总页数
  constructor() {}

  ngOnChanges(changes: SimpleChange) {
    console.log(changes, 'changes')
    // 渲染出分页组件
    if (changes.hasOwnProperty('total') && changes['total'].currentValue) {
      this.total = changes['total'].currentValue
      this.totalPage = Math.ceil(this.total / this.limit)
      this.pagelist = this.getPagelist()
    }
  }

大体流程就是:进入页面父组件获取数据传给组件

  • total 列表总条数
  • limit 每页展示条数
  • curPage 当前页码
  • pageGroup 分页条数
  • totalPage 计算得出总页数 total/limit

上面的属性已经可以正常渲染出分页了,但是由于总条数是假值,我们要做两个验证,

  • 当第一次获取列表接口:父组件获取列表接口返回的列表length是否不足20条,如果不足20条,就只有一页数据,我们直接赋值 列表条数 = 总条数
  • 第一次获取列表接口等于20条,只能是先展示10页数据;当点击第二页或者第3页的时候,再次根据返回的列表是不是20做判断,赋值 列表条数 = 总条数;这里的交互其实只有65条数据,正常4页;但是页面一进来展示10页,当点击第4页的时候分页变成4页。(虽然怪怪的但是是目前想到的办法)
// 当小于20或者为0,代表后面分页无效
if (res.data.reviewJobDetails.length < 20 || res.data.reviewJobDetails.length === 0) {
   this.pageStatus = true
   // 列表条数 = 总条数
   this.newReviewJobTotalCount = searchData.skip + res.data.reviewJobDetails.length
 } else {
   this.reviewJobTotalCount = res.data.totalCount
 }
// 获取列表的接口并没有传page,而是传的skip
skip: this.limit * (this.page - 1)
完结

对于左右箭头极值置灰不可点这里就不说了,最重要的及时getPagelist这个函数,生成中间的页码。好了就到这里啦,完结撒花✿✿ヽ(°▽°)ノ✿

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值