分页在网站中用的比较频繁,现在很多人都喜欢使用第三方组件来快速实现功能,却忽略了其实现原理。这几天抽时间写了个分页组件,功能比较完善,主要包含以下功能:
1,总页数和数据条数
2,可调整显示页码的个数
3,上下和首尾页切换
4,可调整每页显示数据的个数
5,输入指定页面跳转(包括键盘事件(Enter键直接跳转)),限制数据最大不得超过显示页数。
6,当前页为首个或者最后一个时禁止首尾页和上下页选项
创建模板
首先我们还是先来创建HTML模板,模板中:class="{'disabled': current == 1}"是绑定的DOM类,@click="setCurrent(1)绑定的是点击事件,@keyup.enter="submit($event)"绑定的是键盘事件,:style="{width:'28px'}"绑定的是样式。
<template>
<nav>
<span class="pageinfo">共<em>{{pagesum}}</em>页/{{total}}条</span>
<ul class="pagesumnav">
<li :class="{'disabled': current == 1}" @click="setCurrent(1)">首页</li>
<li :class="{'disabled': current == 1}" @click="setCurrent(current-1)">上一页</li>
<li v-for='(num,id) in grouplist' :key='id' @click="setCurrent(num)" :class="{'actived':(current==num)}" :style="{width:'28px'}">{{num}}</li>
<li :class="{'disabled': current == pagesum}" @click="setCurrent(current+1)">下一页</li>
<li :class="{'disabled': current == pagesum}" @click="setCurrent(pagesum)">尾页</li>
</ul>
<div class="pagesumjump">
<select class="pageSelect" @change="pageNum">
<option v-for="(num,ide) in dispaly" :key="ide">{{num}}条/页</option>
</select>
<input type="text" v-model="jumpDefault" @keyup.enter="submit($event)" >
<span @click="jumpTo">跳转</span>
</div>
</nav>
</template>
CSS样式编写
这里就不多阐述了,自己看代码吧,这个应该难不倒大家,主要说下动态的样式:class="{'actived':(current==num)}",在模板中我们绑定了动态样式actived,主要是为了实现当我们点击对应的页码时将背景色及字体颜色更换,让用户一眼就能知道当前在哪页,提供更好的用户体验。还有一个就是:class="{'disabled': current == 1}"样式,这个是用来禁用鼠标事件的。
<style scoped>
.pageinfo em{
font-style: normal;
color:#CA0C16;
padding:2px;
}
.pagesumjump .pageSelect{
padding:4px;
height:29px;
border:none;
outline: none;
background-color:#ccc;
}
.pagesumjump input{
text-align: center;
width:30px;
height: 29px;
margin-left: 3px;
}
.pagesumjump span{
margin-left: 5px;
padding:0 6px;
background-color:#ccc;
border-radius: 3px;
cursor: pointer;
height: 29px;
line-height: 29px;
display: inline-block;
}
.pagesumjump span:hover{
background-color: #CA0C16;
color:#fff;
}
.disabled{
pointer-events: none;
}
.actived{
background-color: #CA0C16;
color:#fff;
}
nav{
margin-top:10px;
display: flex;
justify-content: center;
align-items: center;
}
.pagesumnav{
display: flex;
justify-content: center;
align-items: center;
}
.pagesumnav li{
display: inline-block;
border:1px solid #ccc;
border-radius: 2px;
padding:4px;
margin:0 2px;
cursor: pointer;
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
}
.pagesumnav li:hover{
background-color: #CA0C16;
color:#fff;
}
</style>
功能逻辑实现(重点)
下面是功能的实现,要实现分页功能,我们需要知道我们共有多少条数据,每页显示多少条数据,有多少个分页,显示多少个分页,当前在哪等,给父级修改的我们只需要提供这几个参数:数据总条数、每页显示条数、显示页码数,同时我们需要定义当前页参数(默认为1),显示条数(默认10条),跳转页(默认第1页)
props:{
total:{// 数据总条数
type:Number,
default:10,
},
dispaly:{// 每页显示条数
type:Array,
default(){
return [10,20,30,50]
}
},
pagegroup:{// 显示页码个数
type:Number,
default:5,
},
},
data(){
return{
current: 1,//当前页码
currentSize:this.dispaly[0],//当前显示条数,默认10条
jumpDefault:1, //跳转默认值
}
}
拿到以上几个参数我们开始计算其他数据,接着我们需要知道总共有多少页,根据当前页显示所需的页码。当总页数小于显示页码数时直接显示即可,当当总页数大于显示页码数时我们就需要对当前页进行判断:
当前页在显示页中间的左边时将中心位置移至中间(即处理最前面几个值),当当前页在显示页中间的右边时将中心位置移至中间(即处理最后几个值的)。
computed:{
pagesum(){ // 根据数据的条数和每页显示数量算出总页数,如果没有则为1 ;
return Math.ceil(this.total/this.currentSize) || 1
},
grouplist(){ //获取分页码
var len=this.pagesum
var count=Math.floor(this.pagegroup/2)
var center =this.current
var temp=[]
if(len<this.pagegroup){
while(len--){
temp.push(this.pagesum-len)
}
return temp
}
while(len--){
temp.push(this.pagesum-len)
}
var idx = temp.indexOf(center);
if(idx<=count){
center=center+count-idx
}else if(idx>this.pagesum-count-1){
center=this.pagesum-count
}
var temp=temp.splice(center-count-1,this.pagegroup)
return temp
}
},
监听input框参数,当输入的值大于当前的总页数时只显示总页数值,避免超程现象出现。
watch:{
jumpDefault(){
if(this.jumpDefault>=this.pagesum){
this.jumpDefault=this.pagesum
}
}
},
接下来是页面跳转功能的实现了,pageNum获取我们切换显示数据条数参数,将值赋给currentSize并重置jumpDefault参数和选择页面,setCurrent(idx)跳转页面并将当前页和分页显示数传给父组件。jumpTo跳转按钮功能实现,submit($event)为键盘监听事件。
methods:{
pageNum(){ //切换显示条数
let nums=document.getElementsByClassName('pageSelect')[0].value
var num=nums.split('条')[0]
this.currentSize=num
this.jumpDefault=1
this.setCurrent(1)
},
setCurrent(idx){
// 判断当前页码不等于本身,和大于零,而且要小于总页数的时候,才触发
if (this.current != idx && idx > 0 && idx < this.pagesum + 1) {
this.current = idx;
}
this.$emit('pagedata',{currentpage:this.current,currentSize:this.currentSize})
},
jumpTo(){
this.current=parseInt(this.jumpDefault)
this.setCurrent(this.current)
},
submit($event){
this.jumpTo()
}
}
父组件调用
到这里我们的功能就基本实现了,现在我们在父组件中调用子组件并模拟些数据来测试下效果,因为我子组件传参都给了默认值,所以这里我只传了关键参数:total="num",并监听子组件传回来的数据@pagedata="getpagedata"。
#HTML
<ul class="articalList">
<li v-for="(artical,ide) in articalList" :key="ide">{{artical}}</li>
</ul>
<PageNav @pagedata="getpagedata" :total="num"></PageNav>
#JavaScript
import PageNav from '@/components/pagenav'
created(){
for(let i = 0; i<300 ; i++){
this.temp.push('this is Page design test database : '+i)
}
},
computed:{
num(){
let num =this.temp.length
return num
}
},
components:{
PageNav,
},
methods:{
getpagedata(data){
var current=data.currentpage
var size=data.currentSize
this.articalList=this.temp.slice((current-1)*size,current*size)
}
}
通过getpagedata(data)方法拿到子组件中传回来的当前页和每页显示的数据个数,接着把现实数据筛选出来并赋给循环列表即可将数据渲染出来,下面是显示结果。
欢迎关注本人的公众号:编程手札,文章也会在公众号更新