typora-copy-images-to: media
面向对象案例一-分页
结构分析:
<div>
<div class="first">首页</div>
<div class="prev">上一页</div>
<div class="list">
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>5</p>
</div>
<div class="next">下一页</div>
<div class="last">尾页</div>
</div>
为了好区分每个div
,所以每个div
都加上类名
页码规律分析:
- 总页数小于等于5时,展示页码尾:1~总页数
- 总页数大于5时
- 当前页小于等于3,展示1~5
- 当前页大于等于总页数-2,展示总页数-4~总页数
- 其余情况展示当前页-2~当前页+2
代码分析:
代码基本结构
function Page(classname){
this.box = document.querySelector('.' + classname)
}
var page = new Page(".pagination")
参数分析
- 上一页、下一页、首页、尾页 这些显示的文字,能满足大部分人的需求,但不能满足所有项目的需求,为了让封装好的插件更具适用性,将这些显示的文字作为参数
- 在代码需要用总页数做判断,是需要计算总页数的,公式如下:
总页数 = Math.ceil(数据总条数/每页显示的条数)
,而数据总条数和每页显示的条数又要根据项目的实际情况,也就需要在调用本插件的时候当做参数传传入
由于参数较多,所以将所有参数组成对象传入,即:
function Page(classname,options){
this.box = document.createElement('div') // 自己创建一个div容器
// 将创建好的div容器放到预定好的盒子中
document.querySelector('.' + classname).appendChild(this.box)
// 给创建好的div设置样式
this.setStyle(this.box,{
display:"flex",
justifyContent:"center",
alignItems:"center"
})
}
// 设置样式的方法
Page.prototype.setStyle = function(ele,styleObj){
for(var attr in styleObj){
ele.style[attr] = styleObj[attr]
}
}
// new构造函数并传入需要的实参
var page = new Page(".pagination",{
language:{
first:"首页",
prev:"上一页",
next:"下一页",
last:"尾页"
},
pageData:{
total:100,
pageSize:10
}
})
代码逻辑分析:
参数是可选项,所以要对参数做默认值
function Page(classname,options={}){ // 给options设置默认值
this.box = document.createElement('div') // 自己创建一个div容器
// 将创建好的div容器放到预定好的盒子中
document.querySelector('.' + classname).appendChild(this.box)
// 给创建好的div设置样式
this.setStyle(this.box,{
display:"flex",
justifyContent:"center",
alignItems:"center"
})
// 将传入的options参数作为对象的options属性
this.options = options
// 自定义默认值
this.default = {
language:{
first:"首",
prev:"上",
next:"下",
last:"尾"
},
pageData:{
total:1000,
pageSize:12
}
}
// 调用设置默认值的方法
this.setDefault()
}
// 设置默认值的方法
Page.prototype.setDefault = function(){
// 如果传入的options中传了language键
if(this.options.language){
for(var attr in this.options.language){
// 使用options传入的值替换掉自定义的默认值
this.default.language[attr] = this.options.language[attr]
}
}
if(this.options.pageData){
for(var attr in this.options.pageData){
this.default.pageData[attr] = this.options.pageData[attr]
}
}
}
此时参数就成了可选项
有了参数后,可以计算总页数,定义当前页,....
创建div标签
Page.prototype.createDiv = function(){
for(var attr in this.default.language){
var div = document.createElement('div')
div.innerText = this.default.language[attr];
div.className = attr
this.setStyle(div,{
margin:"5px",
padding:"5px",
border:"1px solid #000"
})
this.box.appendChild(div)
}
}
创建好的标签少了中间放页码的div,所以要在自定义的默认值中,加一个list,用来存放这div
this.default = {
language:{
first:"首",
prev:"上",
list:'',
next:"下",
last:"尾"
},
pageData:{
total:1000,
pageSize:12
}
}
对创建标签的方法进行修改 - 因为放页码的盒子要又不同的样式以及在别的方法中会用到这div,所以将div赋值给一个自定义的属性:
对象新增属性
this.setDefault()
// 总页数属性
this.totalPage = Math.ceil(this.default.pageData.total/this.default.pageData.pageSize)
// 当前页属性 - 当前页默认为1
this.currentPage = 1
// 设置放页码盒子的属性
this.list = null
创建页码的方法修改:
Page.prototype.createDiv = function(){
for(var attr in this.default.language){
var div = document.createElement('div')
if(attr=='list'){ // 如果是list,就将div赋值给自定义的属性list
this.list = div
}else{
// 其余div都设置内容和样式
div.innerText = this.default.language[attr];
this.setStyle(div,{
margin:"5px",
padding:"5px",
border:"1px solid #000"
})
}
div.className = attr // 给每个div添加类名
this.box.appendChild(div) // 将创建好的div放到自己创建好的容器中
}
}
创建页码
Page.prototype.createPage = function(){
if(this.totalPage<=5){
for(var i=1;i<=this.totalPage;i++){
var p = document.createElement('p')
p.innerText = i
if(i==this.currentPage){
p.style.background = 'orange';
}
this.setStyle(p,{
margin:"5px",
padding:'5px',
border:"1px solid #000"
})
this.list.appendChild(p)
}
}else{
if(this.currentPage<=3){
for(var i=1;i<=5;i++){
var p = document.createElement('p')
p.innerText = i
if(i==this.currentPage){
p.style.background = 'orange';
}
this.setStyle(p,{
margin:"5px",
padding:'5px',
border:"1px solid #000"
})
this.list.appendChild(p)
}
}else if(this.currentPage>=this.totalPage-2){
for(var i=this.totalPage-4;i<=this.totalPage;i++){
var p = document.createElement('p')
p.innerText = i
if(i==this.currentPage){
p.style.background = 'orange';
}
this.setStyle(p,{
margin:"5px",
padding:'5px',
border:"1px solid #000"
})
this.list.appendChild(p)
}
}else{
for(var i=this.currentPage-2;i<=this.currentPage+2;i++){
var p = document.createElement('p')
p.innerText = i
if(i==this.currentPage){
p.style.background = 'orange';
}
this.setStyle(p,{
margin:"5px",
padding:'5px',
border:"1px solid #000"
})
this.list.appendChild(p)
}
}
}
}
此时页码显示的样式不能同行显示,所以要在创建好中间的类名叫list
的div
的时候,就应该给他设置好样式:
this.list = div
this.setStyle(div,{
display:"flex",
justifyContent:"center",
alignItems:"center"
})
创建文本框和跳转按钮
Page.prototype.createGo = function(){
var input = document.createElement('input')
input.setAttribute('type','number')
this.setStyle(input,{
width:'44px',
height:'29px',
border:'none',
border:'1px solid #000',
outline:"none",
paddingLeft:'6px',
margin:"5px"
})
this.box.appendChild(input)
var btn = document.createElement('button')
btn.innerText = 'GO';
this.setStyle(btn,{
width:'50px',
border:'none',
border:'1px solid #000',
outline:'none',
height:'33px',
margin:'5px',
background:'#abcdef'
})
this.box.appendChild(btn)
}
点击标签让页码动起来
因为点击的所有子标签都在大盒子中,所以使用事件委托来实现
Page.prototype.clickTag = function(){
this.box.onclick = e=>{
var e = e || window.event;
var target = e.target || e.srcElement;
if(target.className === 'first' && target.getAttribute('disabled') !== 'true'){
this.currentPage = 1
this.list.innerHTML = '';
this.createPage()
this.clickTag()
this.setDisabled()
}else if(target.className === 'last' && target.getAttribute('disabled') !== 'true'){
this.currentPage = this.totalPage-0
this.list.innerHTML = '';
this.createPage()
this.clickTag()
this.setDisabled()
}else if(target.className === 'prev' && target.getAttribute('disabled') !== 'true'){
this.currentPage--
this.list.innerHTML = '';
this.createPage()
this.clickTag()
this.setDisabled()
}else if(target.className === 'next' && target.getAttribute('disabled') !== 'true'){
this.currentPage++
this.list.innerHTML = '';
this.createPage()
this.clickTag()
this.setDisabled()
}else if(target.nodeName === 'P' && target.innerText-0 !== this.currentPage){
this.currentPage = target.innerText - 0
this.list.innerHTML = '';
this.createPage()
this.clickTag()
this.setDisabled()
}else if(target.nodeName === 'BUTTON' && target.previousElementSibling.value-0 !== this.currentPage){
if(target.previousElementSibling.value-0>this.totalPage){
target.previousElementSibling.value = this.totalPage
}
if(target.previousElementSibling.value-0<1){
target.previousElementSibling.value = 1
}
this.currentPage = target.previousElementSibling.value - 0
this.list.innerHTML = '';
this.createPage()
this.clickTag()
this.setDisabled()
this.show(this.currentPage)
}
}
}
在首页的时候不能点击上一页和首页,所以,要设置禁用项,并在每次点击之后,重新加载完页码后要调用禁用项
设置禁用项
Page.prototype.setDisabled = function(){
if(this.currentPage === 1){
this.box.children[0].setAttribute('disabled',true)
this.box.children[1].setAttribute('disabled',true)
this.box.children[0].style.backgroundColor = this.box.children[1].style.backgroundColor = 'gray'
}else{
this.box.children[0].setAttribute('disabled',false)
this.box.children[1].setAttribute('disabled',false)
this.box.children[0].style.backgroundColor = this.box.children[1].style.backgroundColor = 'transparent'
}
if(this.currentPage === this.totalPage){
this.box.children[3].setAttribute('disabled',true)
this.box.children[4].setAttribute('disabled',true)
this.box.children[3].style.backgroundColor = this.box.children[4].style.backgroundColor = 'gray'
}else{
this.box.children[3].setAttribute('disabled',false)
this.box.children[4].setAttribute('disabled',false)
this.box.children[3].style.backgroundColor = this.box.children[4].style.backgroundColor = 'transparent'
}
}
至此,分页插件已经制作完成,需要设置如何使用这个插件
使用插件
数据:
// 生成1000条数据
var firstnameArr = ['赵','钱','孙','李','周','吴','郑','王','冯','陈','褚','卫','蒋','沈','韩','杨']
var secondnameArr = ['甲','乙','丙','丁','戊','己','庚','辛','壬','癸'];
var thirdnameArr = ['子','丑','寅','卯','辰','巳','午','未','申','酉','戌','亥']
var arr = []
for(var i=0;i<1000;i++){
var firstIndex = Math.floor(Math.random()*firstnameArr.length)
var secondIndex = Math.floor(Math.random()*secondnameArr.length)
var thirdIndex = Math.floor(Math.random()*thirdnameArr.length)
var obj = {
name:firstnameArr[firstIndex] + secondnameArr[secondIndex] + thirdnameArr[thirdIndex],
age:Math.floor(Math.random()*100),
sex:['男','女'][Math.floor(Math.random()*2)]
}
arr.push(obj)
}
数据需要通过插件来加载,每页展示的数据需要进行截取后展示在页面中,截取数据的规律如下:截取后的数据 = 数组.slice((当前页-1)*每页展示的条数,当前页*每页展示的条数)
在这公式中,每页展示的条数,是自己决定的,但是当前页需要在插件中才能知道,所以,给插件传入一个函数,让插件来调用这个函数,并将插件中的当前页当做形参传入这个函数,函数中就能使用当前页了
调用时传入一个函数
var pageSize = 10
var page = new Page("pagination",{
language:{
first:"首页",
prev:"上一页",
next:"下一页",
last:"尾页"
},
pageData:{
total:arr.length,
pageSize
},
show:function(currentPage){
document.querySelector('tbody').innerHTML = ''
var res = arr.slice((currentPage-1)*pageSize,currentPage*pageSize)
console.log(res)
for(var i=0;i<res.length;i++){
var tr = document.createElement('tr')
if(i%2===0){
tr.bgColor = 'pink'
}else{
tr.bgColor = 'skyblue';
}
for(var attr in res[i]){
var td = document.createElement('td')
td.innerText = res[i][attr]
tr.appendChild(td)
}
var td = document.createElement('td')
td.innerText = '删除'
tr.appendChild(td)
document.querySelector('tbody').appendChild(tr)
}
}
})
构造函数中处理这个函数
this.default = {
language:{
first:"首",
prev:"上",
list:'',
next:"下",
last:"尾"
},
pageData:{
total:1000,
pageSize:12
},
show:this.options.show || function(){}
}
在每次有了页码后就调用这个函数
this.createDiv()
this.createPage()
this.clickTag()
this.setDisabled()
this.show(this.currentPage)
代码整理
构造函数
function Page(classname,options={}){
// 创建放分页的大盒子
this.box = document.createElement('div')
// 给创建后的大盒子设置样式
this.setStyle(this.box,{
display:"flex",
justifyContent:"center",
alignItems:"center"
})
// 将创建好的大盒子放到在页面中预备好放分页的盒子
document.querySelector('.' + classname).appendChild(this.box)
// 将传入的options参数作为对象的属性
this.options = options
// 定义default属性作为将来要使用的配置参数
this.default = {
language:{
first:"首",
prev:"上",
list:'',
next:"下",
last:"尾"
},
pageData:{
total:1000,
pageSize:12
},
}
// 使用分页插件的show方法作为对象的方法并设置默认值
this.show = this.options.show || function(){}
// 调用方法设置参数尾可选项
this.setDefault()
// 总页数属性
this.totalPage = Math.ceil(this.default.pageData.total/this.default.pageData.pageSize)
// 当前页属性 - 当前页默认为1
this.currentPage = 1
// 设置放页码盒子的属性
this.list = null
// 创建分页中的几个div - 首页、上一页、放页码的div、下一页、尾页
this.createDiv()
// 创建文本框和按钮
this.createGo()
// 调用初始化方法 - 创建页码、点击翻页、设置禁用项、调用传入的使用插件的方法
this.init()
}
初始化方法
// 初始化方法
Page.prototype.init = function(){
// 创建页码
this.createPage()
// 点击翻页
this.clickTag()
// 设置禁用项
this.setDisabled()
// 调用使用插件的方法
this.show(this.currentPage)
}
创建文本框和按钮
// 创建文本框和按钮
Page.prototype.createGo = function(){
// 创建input标签
var input = document.createElement('input')
// 设置input的type属性
input.setAttribute('type','number')
// 给input设置样式
this.setStyle(input,{
width:'44px',
height:'29px',
border:'none',
border:'1px solid #000',
outline:"none",
paddingLeft:'6px',
margin:"5px"
})
// 将input标签放在大盒子中
this.box.appendChild(input)
// 创建按钮
var btn = document.createElement('button')
// 给按钮中放内容
btn.innerText = 'GO';
// 给按钮设置样式
this.setStyle(btn,{
width:'50px',
border:'none',
border:'1px solid #000',
outline:'none',
height:'33px',
margin:'5px',
background:'#abcdef'
})
// 将按钮放如大盒子
this.box.appendChild(btn)
}
设置禁用项
// 设置禁用项
Page.prototype.setDisabled = function(){
// 如果当前是第一页
if(this.currentPage === 1){
// 给首页和上一页设置disabled属性,值为true
this.box.children[0].setAttribute('disabled',true)
this.box.children[1].setAttribute('disabled',true)
// 将首页和上一页的背景设置为灰色
this.box.children[0].style.backgroundColor = this.box.children[1].style.backgroundColor = 'gray'
}else{ // 如果当前不是第一页
// 给首页和上一页设置disabled属性,值尾false
this.box.children[0].setAttribute('disabled',false)
this.box.children[1].setAttribute('disabled',false)
// 将首页和上一页的背景设置为透明
this.box.children[0].style.backgroundColor = this.box.children[1].style.backgroundColor = 'transparent'
}
// 如果当前是最后一页
if(this.currentPage === this.totalPage){
// 给下一页和尾页设置disabled属性,值为true
this.box.children[3].setAttribute('disabled',true)
this.box.children[4].setAttribute('disabled',true)
// 将下一页和尾页的背景设置为灰色
this.box.children[3].style.backgroundColor = this.box.children[4].style.backgroundColor = 'gray'
}else{ // 如果当前不是最后一页
// 给下一页和尾页设置disabled属性,值为false
this.box.children[3].setAttribute('disabled',false)
this.box.children[4].setAttribute('disabled',false)
// 将下一页和尾页的背景设置为透明
this.box.children[3].style.backgroundColor = this.box.children[4].style.backgroundColor = 'transparent'
}
}
点击翻页
// 点击标签翻页 - 使用事件委托
Page.prototype.clickTag = function(){
// 给大盒子绑定单击事件 - 为了能在事件函数中使用的this是外面new的对象,所以使用箭头函数
this.box.onclick = e=>{
// 获取事件对象
var e = e || window.event;
// 通过事件对象获取目标元素
var target = e.target || e.srcElement;
// 如果目标元素是首页,且disabled属性不是true
if(target.className === 'first' && target.getAttribute('disabled') !== 'true'){
// 将当前页设置为1
this.currentPage = 1
// 调用初始化方法
this.init()
// 如果目标元素是尾页,且disabled属性不是true
}else if(target.className === 'last' && target.getAttribute('disabled') !== 'true'){
// 将当前页设置为最后一页
this.currentPage = this.totalPage-0
// 调用初始化方法
this.init()
// 如果目标元素是上一页,且disabled属性不是true
}else if(target.className === 'prev' && target.getAttribute('disabled') !== 'true'){
// 让当前页自减
this.currentPage--
// 限制最小的当前页
if(this.currentPage<=1){
this.currentPage = 1
}
// 调用初始化方法
this.init()
// 如果目标元素是下一页,且disabled属性不是true
}else if(target.className === 'next' && target.getAttribute('disabled') !== 'true'){
// 让当前页自增
this.currentPage++
// 限制最大的当前页
if(this.currentPage>=this.totalPage){
this.currentPage = this.totalPage
}
// 调用初始化方法
this.init()
// 如果目标元素是页码标签p标签且这个页码标签中的数字不是当前页
}else if(target.nodeName === 'P' && target.innerText-0 !== this.currentPage){
// 将当前页设置为当前点击的页码标签中的数字
this.currentPage = target.innerText - 0
// 调用初始化方法
this.init()
// 如果目标元素是按钮且按钮前面的input中输入的数字不是当前页
}else if(target.nodeName === 'BUTTON' && target.previousElementSibling.value-0 !== this.currentPage){
// 如果文本框中的数字大于总页数
if(target.previousElementSibling.value-0>this.totalPage){
// 将输入框中的数字设置为总页数
target.previousElementSibling.value = this.totalPage
}
// 如果文本框中的数字小于1
if(target.previousElementSibling.value-0<1){
// 将输入框中的数字设置为1
target.previousElementSibling.value = 1
}
// 将当前页设置为按钮前面的文本框中输入的数字
this.currentPage = target.previousElementSibling.value - 0
// 调用初始化方法
this.init()
}
}
}
创建页码
// 创建页码
Page.prototype.createPage = function(){
// 将放页码的div中的内容清空
this.list.innerHTML = '';
// 如果总页数不大于5
if(this.totalPage<=5){
// 循环创建1~总页数的页码
for(var i=1;i<=this.totalPage;i++){
// 创建p标签
var p = document.createElement('p')
// 将页码放在p标签中
p.innerText = i
// 如果是当前页
if(i==this.currentPage){
// 将放当前页的p标签设置为橘色
p.style.background = 'orange';
}
// 给所有p标签设置样式
this.setStyle(p,{
margin:"5px",
padding:'5px',
border:"1px solid #000"
})
// 将创建好的每一个p标签放在list页码div中
this.list.appendChild(p)
}
}else{ // 如果当前页大于5
if(this.currentPage<=3){ // 如果当前页小于等于3 - 展示页码为1~5
// 循环前5个页码数字
for(var i=1;i<=5;i++){
// 创建p标签
var p = document.createElement('p')
// 将页码放在p标签中
p.innerText = i
// 如果是当前页
if(i==this.currentPage){
// 将放当前页的p标签设置为橘色
p.style.background = 'orange';
}
// 给所有p标签设置样式
this.setStyle(p,{
margin:"5px",
padding:'5px',
border:"1px solid #000"
})
// 将创建好的每一个p标签放在list页码div中
this.list.appendChild(p)
}
}else if(this.currentPage>=this.totalPage-2){ // 如果当前页是最后3页 - 展示页码为最后5页
// 循环最后5个页码数字
for(var i=this.totalPage-4;i<=this.totalPage;i++){
// 创建p标签
var p = document.createElement('p')
// 将页码放在p标签中
p.innerText = i
// 如果是当前页
if(i==this.currentPage){
// 将放当前页的p标签设置为橘色
p.style.background = 'orange';
}
// 给所有p标签设置样式
this.setStyle(p,{
margin:"5px",
padding:'5px',
border:"1px solid #000"
})
// 将创建好的每一个p标签放在list页码div中
this.list.appendChild(p)
}
}else{ // 当前页是中间的页码,展示页码为当前页-2~当前页+2
// 循环当前页-2~当前页+2这5个页码数字
for(var i=this.currentPage-2;i<=this.currentPage+2;i++){
// 创建p标签
var p = document.createElement('p')
// 将页码放在p标签中
p.innerText = i
// 如果是当前页
if(i==this.currentPage){
// 将放当前页的p标签设置为橘色
p.style.background = 'orange';
}
// 给所有p标签设置样式
this.setStyle(p,{
margin:"5px",
padding:'5px',
border:"1px solid #000"
})
// 将创建好的每一个p标签放在list页码div中
this.list.appendChild(p)
}
}
}
}
创建div
// 创建首页、上一页、放页码的div、下一页、尾页
Page.prototype.createDiv = function(){
// 遍历设置好的配置参数
for(var attr in this.default.language){
// 创建div标签
var div = document.createElement('div')
// 如果是放页码的盒子 - 不放内容
if(attr=='list'){
this.list = div // 将div赋值给设置好的list属性
// 给放页码的div设置样式
this.setStyle(div,{
display:"flex",
justifyContent:"center",
alignItems:"center"
})
}else{ // 如果不是放页码的div
// 给div中放入配置好的内容
div.innerText = this.default.language[attr];
// 给div设置样式
this.setStyle(div,{
margin:"5px",
padding:"5px",
border:"1px solid #000"
})
}
// 给创建好div设置类名
div.className = attr
// 将创建好的div放如大盒子中
this.box.appendChild(div)
}
}
设置配置参数
// 设置配置参数
Page.prototype.setDefault = function(){
// 如果传入的options中有language键
if(this.options.language){
// 遍历传入的language,代替默认的language
for(var attr in this.options.language){
this.default.language[attr] = this.options.language[attr]
}
}
// 如果传入的options中有pageData键
if(this.options.pageData){
// 遍历传入的pageData,代替默认的pageData
for(var attr in this.options.pageData){
this.default.pageData[attr] = this.options.pageData[attr]
}
}
}
设置样式的方法
// 设置样式的方法
Page.prototype.setStyle = function(ele,styleObj){
for(var attr in styleObj){
ele.style[attr] = styleObj[attr]
}
}
最终效果
使用分页插件的效果 |