在使用vue编写完一个分页器组件后,我对分页器的底层逻辑产生了兴趣,想在此组件的基础上再深入了解一些分页器的底层逻辑,了解vue与原生js的区别。我在github上看了一些大神写的分页器,属实牛逼,之后自己也根据他们的编写逻辑,反复推敲了个七八遍,也算是对分页器的逻辑掌握的差不多了,以下则是小编对原生js编写的一些体会。
首先我们需要明白在编写js时,我们需要在页面中创建哪些标签?标签应该赋予什么属性?分页器需要哪些数据?需要哪些函数?函数需要传哪些参数?总之,需要考虑的问题非常多,从构建到渲染再到功能实现都需要亲力亲为的。
页面构建思路:
所有按钮用a标签表示,全部放在一个div盒子中
点击切换的按钮有正常使用的属性值(prevPage和nextPage)和禁用属性值(disabled)
数值页面按钮有选中时的属性值(current)和未选中的属性值
创建出来的html和css代码如下:
html代码:
<div class="page">div>
css代码:
a {
text-decoration: none;
}
.page {
display: table;
margin: 100px auto;
}
.page a {
cursor: default;
display: inline-block;
color: #00C9A6;
background-color: #D9F7F2;
height: 25px;
font-size: 10pt;
line-height: 25px;
padding: 0 9px;
border: 1px solid #D9F7F2;
margin: 0 2px;
border-radius: 4px;
vertical-align: middle;
}
.page a:not(.disabled):not(.current):hover {
border: 1px solid #00C9A6;
cursor: pointer;
}
.page a.current {
display: inline-block;
font-size: 10pt;
height: 25px;
line-height: 25px;
padding: 0 9px;
margin: 0 2px;
color: #fff;
background-color: #00C9A6;
border: 1px solid #00C9A6;
border-radius: 4px;
vertical-align: middle;
}
.page a.disabled {
display: inline-block;
font-size: 10pt;
height: 25px;
line-height: 25px;
padding: 0 9px;
margin: 0 2px;
color: #ddd;
background: #D9F7F2;
border: 1px solid #D9F7F2;
border-radius: 4px;
vertical-align: middle;
cursor: no-drop;
}
功能实现思路:
创建一个分页器函数(Pagination),在它的原型链上编写分页器的功能函数,这样写的好处是可以让所有的对象都能共享原型上的方法,通过构造函数生成的实例所拥有的方法都指向一个函数的索引,节省内存。
创建分页器所需要的数据,并存放在一个对象上(pages)。
pageCount:页面总数
size:单页面数据量
pageNo:当前页
total:总数据量
创建函数:
初始化数据的方法(init):参数(pages)
功能:将要使用的数据在init中初始化,并调用renderPage传入pages对象完成构建分页器
构建页面的方法(renderPage):参数(pages对象)
功能:构建分页器按钮,并调用switchPage实现切换功能
切换页面的方法(switchPage):无参数
功能:实现点击切换功能,调用gotoPage函数实现数值按钮的点击切换效果
跳转页面的方法(gotoPage):参数(current)
功能:根据传入的current值跳转到对应的页面
创建出来的js代码如下:
function Pagination(obj){
this.init(obj)
}
Pagination.prototype={
pages:{
pageCount:0,//页面总数
size:10,//单页面数据量
pageNo:1//当前页
},
//初始化页面数据,参数:obj
init:function(obj){
var pages=this.pages
pages.total=obj.total//总数据量
obj.pageCount=Math.ceil(obj.total/obj.size)//总页码数
pages.container=obj.container//外部容器
pages.pageNo=obj.pageNo//当前页
pages.pageCount=obj.pageCount//总页码数
pages.eleHtml=obj.eleHtml//标签内部值
pages.prevPage=obj.prevPage || 'prevPage'//上一页按钮
pages.nextPage=obj.nextPage || 'nextPage'//下一页按钮
this.renderPage(pages)
},
//构建页面,参数:args
renderPage(args){
var pageContainer=this.selectEle(args.container)
var pageStr='',start,end
//构建左侧点击按钮
if(args.pageNo>1){
pageStr=`上一页`
}else{
pageStr=`上一页`
}
//构建中间页面按钮区域
if(args.pageCount<6){//当总页码数小于6时
for(start=0;start<args.pageCount;start++){
end=start+1
if(end==args.pageNo){
pageStr+=''+end+''
}else{
pageStr+=''+end+''
}
}
}else{//当总页码大于等于6时
start=args.pageNo-1//确认遍历的起始位置为当前页的前一页
end=args.pageNo+1//确认遍历的结束位置为当前页的后一页
if(args.pageNo>2){pageStr+=''+1+''}//当前页大于2时,将页面1按钮写死
else {end =4}//当前页小于等于2时,将遍历的结束位置写死为4
if(args.pageNo>args.pageCount-3){start=args.pageCount-3}//当前页为最后四个页面时,将遍历的起始位置写死为倒数第四个页面值
if(args.pageNo>3){pageStr+='...'}//当前页大于第三个页面时,将省略号按钮展现出来
//对中间按钮进行遍历
for(;start<=end;start++){
if(start<=args.pageCount && start>0){
if(start==args.pageNo){
pageStr+=''+start+''
}else{
pageStr+=''+start+''
}
}
}
if(args.pageNo<args.pageCount-2){pageStr += '...'}//当前页面小于倒数第三个页面时,将省略号按钮展现出来
if(args.pageNo<args.pageCount-1){pageStr+=''+args.pageCount+''}//当前页面小于倒数第二个页面,将最后的页面按钮锁死
}
//构建右侧按钮
if(args.pageNo<args.pageCount){
pageStr+=`下一页`
}else{
pageStr+=`下一页`
}
pageContainer.innerHTML=pageStr
this.switchPage()
},
//切换页面
switchPage(){
var pages=this.pages,g=this
var aList=this.selectEle(pages.container+" a",true)//获取所有的a标签
var current//定义一个当前页的标识
//对所有的a标签遍历,绑定点击事件
for(i in aList){
if(i<aList.length){
aList[i].addEventListener("click",function(){
var eleHtml=this.innerHTML//定义一个属性值来获取数字按钮
if(this.className==pages.prevPage){
pages.pageNo>1 && (pageNo=pages.pageNo-1)
}else if(this.className==pages.nextPage){
pages.pageNo<pages.pageCount && (pageNo=pages.pageNo+1)
}else{
pageNo=parseInt(eleHtml)
}
pageNo && g.gotoPage(pageNo)
})
}
}
},
//跳转页面,参数:current
gotoPage(current){
this.pages.pageNo=current
this.renderPage(this.pages)
},
//获取页面元素
selectEle(select,all){
return all ? document.querySelectorAll(select) : document.querySelector(select)
}
}
var p=new Pagination({
container: '.page',
size: 10,
pageNo: 1,
total: 100
})
代码解释:
实现该分页器的主要逻辑在renderPage函数中,在构建的时候,我们要考虑到当页面数据发生变化时,其样式也要随之变化
(1)首先构建左侧上一页按钮以及右侧下一页按钮,如果当前页面大于1或者小于页码最后一页,两个按钮正常使用,否则则禁用两个按钮
(2)构建中间的数字按钮
(2.1)总页码数小于6时,直接遍历展现出所有的数字按钮
(2.2)总页码数大于6时,令起始值为当前的页码数-1,结束值为当前的页码数+1,再遍历出所有的数字按钮
(2.2.1)当前页大于第二页或者当前页小于倒数第二个页面,分别将1按钮以及最后一个按钮写死。如果当前页小于等于2时,或者当前页为最后四个页面时,为了保证展示的按钮有三个,我们需要将初始值或者结束值写死
(2.2.2)当前页大于第三页或者当前页小于倒数第三个页面,分别展示左侧和右侧的省略号按钮
通过对分页器采用原生js以及用vue,相比较之下我体会到了vue的优势在于:
1.提高了代码的可复用性,以及对代码的维护比较方便,例如,如果我们想添加一个输入框去选择我们想要跳转的页面,在vue中直接添加一个组件,而在原生js中我们需要在构建页面的函数中添加构建输入框的代码,维护性很差。
2.vue将一些常用的js操作封装起来供我们使用,例如v-for就是对js中的for循环进行封装,使用起来更加简便。
3.页面的灵活性更强,例如标签的类名我们可以动态进行赋值来应对页面的数据变化产生相应的样式变化。