QingUI是一个UI组件库
目前拥有的组件:DatePicker, TimePicker, Paginator, Tree, Cascader, Checkbox, Radio, Switch, InputNumber, Input
ES6语法编写,无依赖
原生模块化,Chrome63以上支持,请开启静态服务器预览效果, 静态服务器传送门
采用CSS变量配置样式
辛苦造轮子,欢迎来github仓库star: https://github.com/veedrin/qing
四月份找工做,求内推,坐标深圳
去年年末项目中尝试着写过一个分页的Angular组件,而后就有了写QingUI的想法javascript
过程仍是很是有意思的前端
接下来我会用几篇文章分别介绍每一个组件的大概思路,请你们耐心等待java
这一篇介绍Paginator分页git
最重要的,求star,求fork,求内推github
repo: QingUI
通常的需求是,我有一个列表,可是我不想一下让用户看这么多,一次看一点,再想看,翻到下一页后端
固然如今有无限滚动,只要滚动到必定距离,就给你加载新的数据,这个咱们不考虑数组
分页也有两种作法,一种是一次性加载全部数据,前端作分页;一种是每次加载一部分,点击分页就是触发再次加载的动做服务器
第一种作法应该不多见了吧,首次加载的压力太大模块化
页面初始加载的时候向后台请求数据,请求哪些数据呢?要显示的列表信息,还有当前是第几页函数
若是每页显示多少条是可配置的,那么还须要每页显示多少条和总条数
初始加载确定是第一页
而后用户看完第一页,往下翻,多是翻到第二页,也多是翻到后面的任一页,无所谓
咱们获取到用户想翻到第几页的信息之后,传给后端,后端再把相应页的列表信息传过来,前端展现
注意,这个时候分页是要变的,用户点击的那一页要高亮,以前那一页去掉高亮,若是页数比较多,省略号的位置也要根据规则发生变化
因此咱们得出一个重要信息,分页组件展现页码的那一块每次点击都是要从新渲染的
$bar
就是展现页码的容器,展现页码的模板封装到另外一个函数里
一开始能想到这个,后面就不须要推倒重来了,你猜我有没有推倒重来 :)
tpl += ` <div class="square end prev">﹤</div> <div class="bar"></div> <div class="square end next">﹥</div> `;
若是咱们把展现逻辑放到模板渲染函数里,那模板渲染函数会变得很是繁杂
咱们能够分红两步,第一步构建数据模型,第二步根据数据模型生成模板
我仔细的观察过GitHub(GitHub已经很是优美了)的分页逻辑,QingUI的分页逻辑就是根据GitHub来的
我总结了一下,代码注释里也有:
哦,忘了解释,数据模型是怎么映射的
分页都是从1开始,最大随意(通常不会太大),因此咱们构建一个数组,1到正无穷就表明1到正无穷页,0表明省略号
1到7页之间能够彻底展现,为何?
首尾各1页,中间共5页,加起来就是7页,超过7页就会有省略号
不是说跨度大于等于2页才会有省略号吗?
由于首页和中间的5页是能够重合的,若是有8页,前面5页和最后1页中间正好隔了2页
因此1到7页之间能够彻底展现
for (let i = 1; i <= c; i++) { this.model.push(i); }
若是当前页小于4,至少要保证当前页加左右至少有5页,因此这种状况要单独拎出来
后面再加一个省略号,以及尾页
for (let i = 1; i <= 5; i++) { this.model.push(i); } this.model.push(0, c);
这种状况就是首页和中间5页不重合的状况,因此for循环不须要写死
一样,后面再加一个省略号,以及尾页
for (let i = 1; i <= p + 2; i++) { this.model.push(i); } this.model.push(0, c);
这种状况就是距离首页的跨度大于等于2,距离尾页的跨度也大于等于2,因而先后都有省略号
this.model.push(1, 0); for (let i = p - 2; i <= p + 2; i++) { this.model.push(i); } this.model.push(0, c);
这种状况是说后面没有省略号了,可是也不至于和尾页产生重合
this.model.push(1, 0); for (let i = p - 2; i <= c; i++) { this.model.push(i); }
中间5页与尾页产生重合了,至少要保证渲染出5页,因此for循环写死
this.model.push(1, 0); for (let i = c - 4; i <= c; i++) { this.model.push(i); }
6种状况:
仍是挺有规律的是吧
数据模型代码
buildModel() { // 每次从新初始化 this.model = []; const c = this.pageCount, p = this.position; if (c < 8) { for (let i = 1; i <= c; i++) { this.model.push(i); } } else { if (p < 4) { for (let i = 1; i <= 5; i++) { this.model.push(i); } this.model.push(0, c); } else if (p < 6) { for (let i = 1; i <= p + 2; i++) { this.model.push(i); } this.model.push(0, c); } else { if (p < c - 4) { this.model.push(1, 0); for (let i = p - 2; i <= p + 2; i++) { this.model.push(i); } this.model.push(0, c); } else if (p < c - 1) { this.model.push(1, 0); for (let i = p - 2; i <= c; i++) { this.model.push(i); } } else { this.model.push(1, 0); for (let i = c - 4; i <= c; i++) { this.model.push(i); } } } } }
若是你不喜欢GitHub分页规则,或者本身有特殊的需求
能够根据上面的规律本身定制一套分页逻辑
真的,往上套就能够了
数据模型都构建出来了,渲染就简单了
for (const item of this.model) { if (item > 0) { if (this.position !== item) { tpl += `<div class="square page">${item}</div>`; } else { tpl += `<div class="square page active">${item}</div>`; } } else { tpl += '<div class="square gap">···</div>'; } }
在某些状况,咱们要让用户知道往前或者日后点击是无效的,要进行置灰处理
规则也挺简单的
if (this.position === 1) { this.$prev.classList.add('disabled'); this.$next.classList.remove('disabled'); }
if (this.position === this.pageCount) { this.$next.classList.add('disabled'); this.$prev.classList.remove('disabled'); }
if (this.position === this.pageCount) { this.$prev.classList.remove('disabled'); this.$next.classList.remove('disabled'); }
这种状况很容易被忽略
若是总共只有1页,那左右都点不了,并且当即返回
if (this.pageCount === 1) { this.$prev.classList.add('disabled'); this.$next.classList.add('disabled'); return; }
这里主要是注意一个问题
假如如今的当前页是比较靠后的位置
而后我增长每页显示的条数,那势必总页数就变小了
有可能总页数变的比当前页还小
那么这个时候就只能强制改变当前页,让它变成最后1页了
这就是一个输入框,加keyup监听Enter
键的事件
Paginator比较核心的逻辑就在这里了
最有意思的是构建数据模型的那一段,挺费脑子的
下一篇文章介绍Tree,敬请期待
最后,求star,求fork,求内推
repo: QingUI