写在前面
最近,朋友让我帮他封装一个原生js分页组件。
我说,基于jQuery的框架那么多,你随便找一个框架的分页组件拿来用不就完了吗?
他说,不要,他不想用jQuery,他就要用原生。
我说,哦,那好呗,网上那么多大佬的原生组件,你随便找一个用不也行吗?
他说,他找了很多,但有的缺这个功能,有的缺那个功能,都不是他想要的。
我想了想,我还没有封装过原生js组件,帮他弄一个也是我自己一个学习的过程。
我说,好。
效果预览
使用
① 输入命令: npm install chris_paging 即可安装npm包。
② 在要使用本组件的地方增加如下代码(注意相对路径):
<div class="chris_pagingArea"></div>
<script src="./node_modules/chris_paging/paging.js"></script>
③ 实例化,并按需要设置配置项:
<script>
var paging = new chris_paging({
totalCount: 200,//总数据量
boxCount: 6,//页面上切换页码的盒子数(包括“...”),最少6块
selectOptionsArray: ['10', '20', '30'],//设置一页多少条选项的数组
show_totalCount: true,//是否展示总记录数 (1)
show_main_pages: true,//是否展示详细页码区域(2)
show_pagesCount: true,//是否展示当前页码/总页数(3)
show_pagesOptionSelectArea: true,//是否展示一页多少条的选择框(4)
show_refreshBtn: true,//是否展示刷新按钮(5)
show_changePageArea: true,//是否展示快速跳转页码区域(6)
onPrePage: function (currentPage, eachPageCount) {
console.log('点击上一页按钮')
console.log('当前第' + currentPage + '页,每页' + eachPageCount + '条')
},
onPagesNum: function (currentPage, eachPageCount) {
console.log('当前点击:第' + currentPage + '页')
console.log('每页' + eachPageCount + '条')
},
onAftPage: function (currentPage, eachPageCount) {
console.log('点击下一页按钮')
console.log('当前第' + currentPage + '页,每页' + eachPageCount + '条')
},
onChangeEachPageCount: function (eachPageCount) {
console.log('点击切换为' + eachPageCount + '条/页')
},
onRefreshBtn: function (currentPage, eachPageCount) {
console.log('点击刷新按钮')
console.log('当前第' + currentPage + '页,每页' + eachPageCount + '条')
},
onConfirmBtn: function (currentPage, eachPageCount) {
console.log('点击确定按钮,跳转到第' + currentPage + '页')
console.log('每页' + eachPageCount + '条')
}
});
</script>
关于配置项的具体说明
首先,上述配置项都是非必填项。
由于我做了初始值的处理,所以基本不必担心会有未定义的报错。但是因为个人需要的功能不同,因此所有操作区域的载入默认都是false,请大家根据自己的需求把相关区域的载入配置为true。
上图中一共有六块区域,每块区域的注释中,括号内的数字对应下图中圈出的数字:
我觉得这样一划大家都能看懂了吧,然后几个function分别对应什么效果也都写了注释,我这里只处理了关于页码的切换效果,大家在使用的时候需要把对数据的处理写到对应的点击事件里,比如点击下一页的时候发请求请求接下来的数据啊等等
注意
上述配置项中有一个boxCount,可能会有误解的地方,因此这里单独拿出来说一下:
这个是指页码的盒子的数量,也就是上面划出来的第二块区域。那么为什么我限制它最少为6块呢?
我贴一张图大家就明白了:
这是5块的时候的样子,虽然还能放下,但是效果已经不好了,因为只能看到首页末页和当前页;就更别说4块的时候,如果要显示首页末页和前后两个省略号,都没有地方显示当前页了。所以最好的效果就是大于6块的,因此这边才要求最少为6块。
另外使用组件的时候请注意全局css污染问题,我这里的类名都加了自己的前缀,应该不会有问题,也请外部css避免直接给标签写样式。
小结
这是一次原生组件封装的尝试,因此会有很多不足的地方,也有很多不漂亮的代码,希望大家使用过程中碰到问题或者有什么建议可以反馈给我,不胜感激。
目前本组件版本1.0.3,如果后续大家在使用过程中想要更多功能或其他优化等也可以联系我维护更新版本~
P.S: 源码后没有内容了哦,不需要源码的小伙伴们到这就可以不用往下看啦~
源码
因为考虑到有些小伙伴不想使用npm,因此这里也直接提供源码。有个刷新按钮的图片,自己看一下路径,去做个这个图哦~(本来想放github地址,后来想想万一人家也不愿意用github那咋办。。。)
/* chris_paging/paging.css */
.chris_pagingArea {
display: flex;
flex-direction: row;
align-items: center;
font-family: Microsoft YaHei;
font-weight: 400;
color: #666;
margin: 20px 0 82px;
white-space: nowrap;
}
.chris_pagingArea_totalCount,
.chris_pagingArea_pagesCount {
font-size: 14px;
}
.chris_pagingArea_totalCount {
margin-right: 8px;
}
.chris_pagingArea_pagesCount {
width: 105px;
text-align: center;
margin-right: 8px;
}
.chris_pagingArea_setEachPageCount {
width: 80px;
height: 28px;
border: 1px solid #DEE2E6;
font-size: 12px;
padding-left: 10px;
margin-right: 16px;
}
.chris_pagingArea_choosePageArea {
margin-right: 8px;
font-size: 12px;
}
.chris_pagingArea_choosePageArea input {
width: 26px;
height: 24px;
text-align: center;
outline: none;
font-size: 12px;
margin: 0 8px;
}
.chris_choosePageBtn {
width: 52px;
height: 28px;
border: 1px solid #DEE2E6;
font-size: 12px;
text-align: center;
line-height: 28px;
cursor: pointer;
}
.chris_pagingArea_main {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 8px;
}
.chris_pagingArea_main_preBtn,
.chris_pagingArea_main_NextBtn {
width: 80px;
height: 28px;
border: 1px solid #DEE2E6;
font-size: 12px;
text-align: center;
line-height: 28px;
cursor: pointer;
}
.chris_pagingArea_main_preBtn {
color: #999;
}
.chris_noSelect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.chris_pagingArea_main_NextBtn {
border-left: 0;
}
.chris_pages_box {
width: 30px;
height: 28px;
border: 1px solid #DEE2E6;
border-left: 0;
text-align: center;
line-height: 28px;
cursor: pointer;
}
.chris_pagingArea_main_pages {
display: flex;
flex-direction: row;
align-items: center;
}
.chris_pages_box_checked {
background-color: #E22323;
color: #fff;
}
.chris_pagingArea_refreshBtn {
width: 14px;
height: 14px;
margin-right: 3px;
cursor: pointer;
}
// chris_paging/paging.js
; (function (undefined) {
"use strict"
var _global;
var scripts = document.getElementsByTagName("script")
var script = scripts[scripts.length - 1];
var locationStr = document.querySelector ? script.src : script.getAttribute("src", 4);
document.write('<link rel="stylesheet" href="'+ locationStr.split('chris_paging')[0] + 'chris_paging/paging.css">');
function chris_paging(option) {
this._initial(option);
}
chris_paging.prototype = {
constructor: this,
_initial: function (option) {
var def = {
totalCount: 0,
boxCount: 6,
selectOptionsArray: ['10'],
show_totalCount: false,
show_main_pages: false,
show_pagesCount: false,
show_pagesOptionSelectArea: false,
show_refreshBtn: false,
show_changePageArea: false,
onPrePage: function () { },
onAftPage: function () { },
onPagesNum: function () { },
onChangeEachPageCount: function () { },
onRefreshBtn: function () { },
onConfirmBtn: function () { },
};
var currentPage = 1;
var totalCount = option.totalCount ? option.totalCount : def.totalCount;
var boxCount = option.boxCount ? option.boxCount : def.boxCount;
var selectOptionsArray = option.selectOptionsArray ? option.selectOptionsArray : def.selectOptionsArray;
var show_totalCount = option.show_totalCount ? option.show_totalCount : def.show_totalCount;
var show_main_pages = option.show_main_pages ? option.show_main_pages : def.show_main_pages;
var show_pagesCount = option.show_pagesCount ? option.show_pagesCount : def.show_pagesCount;
var show_pagesOptionSelectArea = option.show_pagesOptionSelectArea ? option.show_pagesOptionSelectArea : def.show_pagesOptionSelectArea;
var show_refreshBtn = option.show_refreshBtn ? option.show_refreshBtn : def.show_refreshBtn;
var show_changePageArea = option.show_changePageArea ? option.show_changePageArea : def.show_changePageArea;
var onPrePage = option.onPrePage ? option.onPrePage : def.onPrePage;
var onAftPage = option.onAftPage ? option.onAftPage : def.onAftPage;
var onPagesNum = option.onPagesNum ? option.onPagesNum : def.onPagesNum;
var onChangeEachPageCount = option.onChangeEachPageCount ? option.onChangeEachPageCount : def.onChangeEachPageCount;
var onRefreshBtn = option.onRefreshBtn ? option.onRefreshBtn : def.onRefreshBtn;
var onConfirmBtn = option.onConfirmBtn ? option.onConfirmBtn : def.onConfirmBtn;
var pagingArea = document.getElementsByClassName("chris_pagingArea")[0];
var totalCountArea = document.createElement('div');
totalCountArea.className = 'chris_pagingArea_totalCount';
if (show_totalCount) {
pagingArea.appendChild(totalCountArea);
}
var mainArea = document.createElement('div');
mainArea.className = 'chris_pagingArea_main';
mainArea.classList.add('chris_noSelect');
pagingArea.appendChild(mainArea);
var pages_preBtn = document.createElement('div');
pages_preBtn.className = 'chris_pagingArea_main_preBtn';
pages_preBtn.innerHTML = '上一页';
mainArea.appendChild(pages_preBtn);
var main_pages = document.createElement('div');
main_pages.className = 'chris_pagingArea_main_pages';
if (show_main_pages) {
mainArea.appendChild(main_pages);
}
var pages_nextBtn = document.createElement('div');
pages_nextBtn.className = 'chris_pagingArea_main_NextBtn';
pages_nextBtn.innerHTML = '下一页';
mainArea.appendChild(pages_nextBtn);
var pagesCountArea = document.createElement('div');
pagesCountArea.className = 'chris_pagingArea_pagesCount';
if (show_pagesCount) {
pagingArea.appendChild(pagesCountArea);
}
var selectArea = document.createElement('select');
selectArea.className = 'chris_pagingArea_setEachPageCount';
if (show_pagesOptionSelectArea) {
pagingArea.appendChild(selectArea);
}
var refreshBtn = document.createElement('img');
refreshBtn.className = 'chris_pagingArea_refreshBtn';
refreshBtn.src = 'images/refresh_icon.png';
refreshBtn.addEventListener('click', function () { onRefreshBtn(currentPage, eachPageCount) });
if (show_refreshBtn) {
pagingArea.appendChild(refreshBtn);
}
var choosePageArea = document.createElement('div');
choosePageArea.className = 'chris_pagingArea_choosePageArea';
var tempSpanPre = document.createElement('span');
tempSpanPre.innerHTML = '到第';
choosePageArea.appendChild(tempSpanPre);
var pagesInput = document.createElement('input');
pagesInput.maxLength = 2;
pagesInput.addEventListener('keyup', function () { this.value = this.value.replace(/[^\d]/g, '') });
pagesInput.addEventListener('afterpaste', function () { this.value = this.value.replace(/[^\d]/g, '') });
choosePageArea.appendChild(pagesInput);
var tempSpanAft = document.createElement('span');
tempSpanAft.innerHTML = '页';
choosePageArea.appendChild(tempSpanAft);
var choosePageBtn = document.createElement('div');
choosePageBtn.className = 'chris_choosePageBtn';
choosePageBtn.innerHTML = '确定';
choosePageBtn.classList.add('chris_noSelect');
if (show_changePageArea) {
pagingArea.appendChild(choosePageArea);
pagingArea.appendChild(choosePageBtn);
}
if (boxCount <= 5) {
boxCount = 6;
}
for (var i = 0; i < selectOptionsArray.length; i++) {
var selectOption = document.createElement('option');
selectOption.innerHTML = selectOptionsArray[i] + "条/页";
selectOption.value = selectOptionsArray[i];
selectArea.appendChild(selectOption);
}
var eachPageCount = selectArea.options[selectArea.selectedIndex].value;
selectArea.onchange = function () {
eachPageCount = selectArea.options[selectArea.selectedIndex].value;
currentPage = 1;
initPagesBox();
onChangeEachPageCount(eachPageCount);
}
initPagesBox();
function initPagesBox() {
var pageCount = totalCount == 0 ? 1 : Math.ceil(totalCount / eachPageCount);
totalCountArea.innerHTML = '总记录数:' + totalCount;
pagesCountArea.innerHTML = '第' + currentPage + '页 / 共' + pageCount + '页';
setPagesBox();
function setPagesBox() {
if (currentPage == 1) {
pages_preBtn.style.color = '#999';
pages_nextBtn.style.color = '#666';
if (pageCount == 1) {
pages_preBtn.style.color = '#999';
pages_nextBtn.style.color = '#999';
}
} else if (currentPage == pageCount) {
pages_preBtn.style.color = '#666';
pages_nextBtn.style.color = '#999';
} else {
pages_preBtn.style.color = '#666';
pages_nextBtn.style.color = '#666';
}
pagesCountArea.innerHTML = '第' + currentPage + '页 / 共' + pageCount + '页';
main_pages.innerHTML = '';
var tempInnerHTML = '';
for (var i = 1; i < pageCount + 1; i++) {
if (pageCount <= boxCount) {
tempInnerHTML += '<div class="chris_pages_box">' + i + '</div>';
} else {
if (currentPage <= boxCount - 2) {
if (i <= boxCount - 2) {
tempInnerHTML += '<div class="chris_pages_box">' + i + '</div>';
} else if (i == boxCount - 1) {
tempInnerHTML += '<div class="chris_pages_box">...</div>';
} else if (i == boxCount) {
tempInnerHTML += '<div class="chris_pages_box">' + pageCount + '</div>';
}
} else if (currentPage > pageCount - (boxCount - 2)) {
if (i >= pageCount - (boxCount - 3)) {
tempInnerHTML += '<div class="chris_pages_box">' + i + '</div>';
} else if (i == pageCount - (boxCount - 2)) {
tempInnerHTML += '<div class="chris_pages_box">...</div>';
} else if (i == pageCount - (boxCount - 1)) {
tempInnerHTML += '<div class="chris_pages_box">1</div>';
}
} else {
if (i == currentPage) {
if (boxCount > 4) {
tempInnerHTML += '<div class="chris_pages_box">1</div><div class="chris_pages_box">...</div>';
for (var j = 0; j < boxCount - 4; j++) {
tempInnerHTML += '<div class="chris_pages_box">' + (i + j) + '</div>';
}
tempInnerHTML += '<div class="chris_pages_box">...</div><div class="chris_pages_box">' + pageCount + '</div>';
}
}
}
}
}
main_pages.innerHTML = tempInnerHTML;
setPageBoxClick();
}
setPageBoxClick();
function setPageBoxClick() {
var pages_box = document.getElementsByClassName('chris_pages_box');
if (pages_box.length > 0) {
for (i = 0; i < pages_box.length; i++) {
pages_box[i].onclick = (function (i) {
return function () {
if (pages_box[i].innerHTML != '...') {
for (var j = 0; j < pages_box.length; j++) {
pages_box[j].classList.remove('chris_pages_box_checked');
}
currentPage = parseInt(pages_box[i].innerHTML);
if (currentPage == 1 || currentPage == pageCount) {
setPagesBox();
} else {
pages_preBtn.style.color = '#666';
pages_nextBtn.style.color = '#666';
}
pagesCountArea.innerHTML = '第' + currentPage + '页 / 共' + pageCount + '页';
pages_box[i].classList.add('chris_pages_box_checked');
}
onPagesNum(currentPage, eachPageCount);
}
})(i)
}
}
//点击上一页
pages_preBtn.onclick = function () {
if (currentPage == 1) {
return;
}
currentPage -= 1;
setPagesBox();
setPagesBoxCheckedStyle();
onPrePage(currentPage, eachPageCount);
};
//点击下一页
pages_nextBtn.onclick = function () {
if (currentPage == pageCount) {
return;
}
currentPage += 1;
setPagesBox();
setPagesBoxCheckedStyle();
onAftPage(currentPage, eachPageCount);
};
}
var pages_box = document.getElementsByClassName('chris_pages_box');
if (pages_box.length > 0) {
pages_box[0].classList.add('chris_pages_box_checked');
}
//点击确定按钮,跳转页码
choosePageBtn.onclick = function () {
if (!pagesInput.value) {
return;
}
if (pagesInput.value > pageCount || pagesInput.value < 0) {
alert('请输入正确的页码');
return;
} else {
currentPage = parseInt(pagesInput.value);
setPagesBox();
setPagesBoxCheckedStyle();
}
onConfirmBtn(currentPage, eachPageCount);
}
function setPagesBoxCheckedStyle() {
let tempArray = [];
for (var i = 0; i < pages_box.length; i++) {
tempArray.push(pages_box[i].innerHTML);
}
for (var j = 0; j < pages_box.length; j++) {
pages_box[j].classList.remove('chris_pages_box_checked');
}
for (var i = 0; i < tempArray.length; i++) {
if (tempArray[i] == currentPage) {
pages_box[i].classList.add('chris_pages_box_checked');
}
}
}
}
}
};
_global = (function () { return this || (0, eval)('this'); }());
if (typeof module !== "undefined" && module.exports) {
module.exports = chris_paging;
} else if (typeof define === "function" && define.amd) {
define(function () { return chris_paging; });
} else {
!('chris_paging' in _global) && (_global.chris_paging = chris_paging);
}
}());