背景
项目中的审核系统每天都有至少十几万条数据需要审核,因此列表的分页会有几万页,虽说数据还可以但是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这个函数,生成中间的页码。好了就到这里啦,完结撒花✿✿ヽ(°▽°)ノ✿