分页是WEB开发中很常用的功能,尤其是在各种前后端分离的今天,后端API返回数据,前端根据数据的count以及当前页码pageIndex来计算分页页码并渲染到页面上已经是一个很普通很常见的功能了。从最开始的jquery时代到现在的各种各样的前端框架时代,分页功能都是必不可少的。
分页大多数(基本上)情况下都是对异步数据列表的处理,这里首先需要明白一下分页的流程。
在已知每页显示数据量pageSize以及当前页码pageIndex的情况下:
- 请求API,返回第一屏数据(pageSize内)以及所有相关条件的数据总量count
- 将数据总量传递给page组件,来计算页码并渲染到页面上
- 点击页码,发送请求获取该页码的数据,返回数据总量count以及该页码下的数据条目。
由于获取数据条件的变化(假设是个搜索,关键词变了),count是不定的;再或者,有个select下拉框,来控制每页显示的数据量pageSize,当它变化的时候,总页码肯定也是要变化的。因此很多情况下要重新计算页码并渲染。
了解了流程,在Vue中实现一个分页组件也就变得简单了。
简单处理,样式类似于bootstrap的分页组件,在第一页时,禁用上一页,以及首页按钮;在最后一页时,禁用下一页,以及尾页按钮;超出范围的页码以…来代替,效果图如下:
由于获取数据条件的变化(假设是个搜索,关键词变了),count是不定的;再或者,有个select下拉框,来控制每页显示的数据量pageSize,当它变化的时候,总页码肯定也是要变化的。因此很多情况下要重新计算页码并渲染。
了解了流程,在Vue中实现一个分页组件也就变得简单了。
简单处理,样式类似于bootstrap的分页组件,在第一页时,禁用上一页,以及首页按钮;在最后一页时,禁用下一页,以及尾页按钮;超出范围的页码以…来代替,效果图如下:
分页组件 template
-
<!-- first --> <li :class="['paging-item','paging-item--first',{'paging-item--disabled' : index === 1}]" @click="first">first</li> <li :class="['paging-item','paging-item--more']" v-if="showPrevMore">...</li> <li :class="['paging-item',{'paging-item--current' : index === pager}]" v-for="pager in pagers" @click="go(pager)">{{ pager }}</li> <li :class="['paging-item','paging-item--more']" v-if="showNextMore">...</li> <!-- last --> <li :class="['paging-item','paging-item--last',{'paging-item--disabled' : index === pages}]" @click="last">last</li> <!-- next --> <li :class="['paging-item','paging-item--next',{'paging-item--disabled' : index === pages}]" @click="next">next</li>
style(scss)
javascript
//页面中的可见页码,其他的以...替代,必须是奇数
perPages : {
type : Number,default : 5
},//当前页码
pageIndex : {
type : Number,default : 1
},//每页显示条数
pageSize : {
type : Number,default : 10
},//总记录数
total : {
type : Number,},methods : {
prev(){
if (this.index > 1) {
this.go(this.index - 1)
}
},next(){
if (this.index < this.pages) {
this.go(this.index + 1)
}
},first(){
if (this.index !== 1) {
this.go(1)
}
},last(){
if (this.index != this.pages) {
this.go(this.pages)
}
},go (page) {
if (this.index !== page) {
this.index = page
//父组件通过change<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>来接受当前的<a href="/tag/yema/" target="_blank" class="keywords">页码</a>
this.$emit('change',this.index)
}
}
},computed : {
//计算总<a href="/tag/yema/" target="_blank" class="keywords">页码</a>
pages(){
return Math.ceil(this.size / this.limit)
},//计算<a href="/tag/yema/" target="_blank" class="keywords">页码</a>,当count等变化时<a href="/tag/zidong/" target="_blank" class="keywords">自动</a>计算
pagers () {
const array = []
const perPages = this.perPages
const pageCount = this.pages
let current = this.index
const _offset = (perPages - 1) / 2
const offset = {
start : current - _offset,end : current + _offset
}
//-1,3
if (offset.start < 1) {
offset.end = offset.end + (1 - offset.start)
offset.start = 1
}
if (offset.end > pageCount) {
offset.start = offset.start - (offset.end - pageCount)
offset.end = pageCount
}
if (offset.start < 1) offset.start = 1
this.showPrevMore = (offset.start > 1)
this.showNextMore = (offset.end < pageCount)
for (let i = offset.start; i <= offset.end; i++) {
array.push(i)
}
return array
}
},data () {
return {
index : this.pageIndex,//当前页码
limit : this.pageSize,//每页显示条数
size : this.total || 1,//总记录数
showPrevMore : false,showNextMore : false
}
},watch : {
pageIndex(val) {
this.index = val || 1
},pageSize(val) {
this.limit = val || 10
},total(val) {
this.size = val || 1
}
}
}
父组件中使用