分页组件
功能需求:
- 根据数据内容,按照每页显示固定数量的内容,完成页面布局;
- 根据数据内容,自动创建页码内容;
- 点击页码时,完成每页显示固定数量内容的翻页效果;
- 每页显示的内容数量可以自定义;
- 当显示第一页时,上一页按钮不能点击;当显示最后一页时,下一页按钮不能点击;
来看一下效果:
分析:
- 因为页码是自动创建的,无法对页码元素进行事件监听,只能使用事件委托来做;
- 当点击页码后,要考虑三个操作,一是页码的显示状态,二是页面中内容的显示,三是上一页按钮跟下一页按钮的显示状态和点击状态;
- 点击页码后,先将页面中的内容清除,再放入新的内容;
- 由于使用了事件委托机制,在点击的时候,需要确定当前操作的元素是页码还是上下页按钮;
- 当数据内容较多时,页码内容可以做成轮播图的效果,或者将中间部分页码以 省略号 的形式来显示,这个功能暂时还没有实现,大家可以自己做一下。
下面附上代码:
html结构:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>page</title>
</head>
<body>
<script type="module">
import Main from "./js/Main.js";
init();
function init(){
//第一个参数为每一页要展示的数量,不传默认是50,第二个参数为一共有多少数据,不传默认是143
let main=new Main(50,305);
main.appendTo("body");
}
</script>
</body>
</html>
Main.js文件:用来创建页面中要显示的内容。
import Utils from './Utils.js';
import Page from './Page.js';
export default class Main{
resultData=[];
content;
static GET_RESULT_DATA="get_result_data";
constructor(_num,_dataLength){
//监听事件,初始化页面内容
document.addEventListener(Main.GET_RESULT_DATA,e=>this.getResultData(e));
//创建外层div
this.elem=this.createElem();
//实例化页码
let page=new Page(_num,_dataLength);
Utils.appendTo(page.elem,this.elem);
}
createElem(){
if(this.elem) return this.elem;
let div=Utils.createE("div")
return div;
}
appendTo(parent){
Utils.appendTo(this.elem,parent);
}
getResultData(e){
//获取传递过来的数据
this.resultData=e.data;
//创建页面内容
this.createCont();
}
createCont(){
//如果页面中已经有内容,则先清除内容,再放入新的内容
if(this.content) this.content.remove();
//创建content容器
this.content=Utils.createE("div",{
width:"500px",
height:"250px",
border:"1px solid #000",
});
//根据resultData,创建每一页要显示内容
this.resultData.forEach(item=>{
let span=Utils.createE("span",{
display:"inline-block",
width:"50px",
height:"50px",
textAlign:"center",
lineHeight:"50px"
},{
textContent:item
})
Utils.appendTo(span,this.content);
})
//插入在页码容器的前面
this.elem.insertBefore(this.content,this.elem.firstElementChild)
}
}
Page.js文件:按照数据生成页码,完成对页码的点击操作。
import Utils from "./Utils.js";
export default class Page{
num;//每一页的数量
dataLength;//一共有多少数据
position=1;//表示当前第几页
pageList=[];//页码的数组
nextClickBool=false;//控制下一页按钮是否能点击
preClickBool=false;//控制上一页按钮是否能点击
prepPage;
static stylesCss=false;
static GET_RESULT_DATA="get_result_data";
constructor(_num=50,_dataLength=143){
//参数设置默认值
this.num=_num;
this.dataLength=_dataLength;
//创建外层div
this.elem=this.createElem();
//抛发事件,设置页面初始内容
this.setContent();
}
createElem(){
if(this.elem) return this.elem;
//外层的div容器
let div=Utils.createE("div");
div.className="pageContainer";
div.innerHTML=`<a href="javascript:void(0)" class="disabled" id="preBtn"><上一页</a>${this.setPageCon()}
<a href="javascript:void(0)" id="nextBtn">下一页></a>`;
//设置样式
Page.setStyles();
//获取元素
Utils.getIdElem(div,this);
//页码监听点击事件
div.addEventListener("click",e=>this.clickHandler(e));
return div;
}
appendTo(parent){
Utils.appendTo(this.elem,parent);
}
setPageCon(){
//设置页码内容
let str="";
//计算一共有多少页
for(let i=0;i<Math.ceil(this.dataLength/this.num);i++){
str+=`<a href="javascript:void(0)" class="${i===0?'active':''}">${i+1}</a>`
}
return str;
}
clickHandler(e){
if(e.target.nodeName!="A") return;
//获取到只有页码的数组,赋值给this.pageList
let arr=document.querySelectorAll("a");
this.pageList=Array.prototype.slice.call(arr).slice(1,arr.length-1);
//设置this.prepPage默认为第1个按钮
this.prepPage=this.pageList[this.position-1];
//判断当前操作的元素
switch (e.target.innerText){
case "<上一页":
if(this.preClickBool) return;
this.nextClickBool=false;
this.position--;
if(this.position<=1) {
this.position=1;
this.preClickBool=true;
}
break;
case "下一页>":
if(this.nextClickBool) return;
this.preClickBool=false;
this.position++;
if(this.position>=this.pageList.length){
this.position=this.pageList.length;
this.nextClickBool=true;
}
break;
default:
this.position=Number(e.target.innerText);
this.preClickBool=false;
this.nextClickBool=false;
break;
}
//设置页码的样式
this.setPageStyles();
//设置显示的内容
this.setContent();
//设置上一页、下一页按钮的样式
this.setBtnState();
}
setPageStyles(){
//将上一个点击的页码按钮,移除active样式
if(this.prepPage) this.prepPage.className="";
//将当前点击的页码按钮,赋值给this.prePage
this.prepPage=this.pageList[this.position-1];
//给当前点击的页面按钮,添加active样式
this.prepPage.className="active";
}
setContent(){
let resultArr=[];
for(let i=(this.position-1)*this.num;i<this.position*this.num;i++){
//如果i大于数据的长度,则不把它添加到resultArr中
if(i>=this.dataLength) continue;
resultArr.push(i);
}
//抛发事件,设置初始化数据
let evt=new Event(Page.GET_RESULT_DATA);
evt.data=resultArr;
document.dispatchEvent(evt);
}
setBtnState(){
//如果当前是第1页,给上一页按钮添加disabled样式
if(this.position==1) this.preBtn.className="disabled";
else this.preBtn.className="";
//如果当前是最后一页,给下一页按钮添加disabled样式
if(this.position==this.pageList.length) this.nextBtn.className="disabled";
else this.nextBtn.className="";
}
static setStyles(){
if(Page.stylesCss) return;
Page.stylesCss=true;
Utils.insertCss(".pageContainer",{
marginTop:"30px"
})
Utils.insertCss(".pageContainer a",{
textDecoration:"none",
display:"inline-block",
minWidth:"10px",
textAlign:"center",
padding:"5px 10px",
borderRadius:"7px",
marginRight:"3px",
backgroundColor:"#fff",
color:"#818287",
border:"1px solid #f6f6f6",
userSelect:"none"
})
Utils.insertCss(".pageContainer a:hover",{
backgroundColor:"rgba(233,37,56,.3)",
color:"#fff"
})
Utils.insertCss(".pageContainer a.disabled",{
backgroundColor:"#f2f2f2",
borderColor:"#d9d9d9",
color:"#ccc"
})
Utils.insertCss(".pageContainer a.active",{
backgroundColor:"#e92538",
borderColor:"#e92538",
color:"#fff",
})
}
}
Utils.js文件:是一个工具包文件。
export default class Utils{
static createE(elem,style,prep){
elem=document.createElement(elem);
if(style) for(let prop in style) elem.style[prop]=style[prop];
if(prep) for(let prop in prep) elem[prop]=prep[prop];
return elem;
}
static appendTo(elem,parent){
if (parent.constructor === String) parent = document.querySelector(parent);
parent.appendChild(elem);
}
static randomNum(min,max){
return Math.floor(Math.random*(max-min)+min);
}
static randomColor(alpha){
alpha=alpha||Math.random().toFixed(1);
if(isNaN(alpha)) alpha=1;
if(alpha>1) alpha=1;
if(alpha<0) alpha=0;
let col="rgba(";
for(let i=0;i<3;i++){
col+=Utils.randomNum(0,256)+",";
}
col+=alpha+")";
return col;
}
static insertCss(select,styles){
if(document.styleSheets.length===0){
let styleS=Utils.createE("style");
Utils.appendTo(styleS,document.head);
}
let styleSheet=document.styleSheets[document.styleSheets.length-1];
let str=select+"{";
for(var prop in styles){
str+=prop.replace(/[A-Z]/g,function(item){
return "-"+item.toLocaleLowerCase();
})+":"+styles[prop]+";";
}
str+="}"
styleSheet.insertRule(str,styleSheet.cssRules.length);
}
static getIdElem(elem,obj){
if(elem.id) obj[elem.id]=elem;
if(elem.children.length===0) return obj;
for(let i=0;i<elem.children.length;i++){
Utils.getIdElem(elem.children[i],obj);
}
}
}