- 代码优劣势
- 版本1(推荐)
- 思路
- 参数说明(来源父传子)
- 完整代码
- 版本2(自写)
- 思路
- 参数说明(来源父传子)
- 完整代码
说明:主要表述分页显示效果时的思路
代码优劣势
- 版本2优势
- 如果总页码数量够多(大于等于9页),那么从进入页面开始到切换任意某个页面时,分页器的DOM都是固定的,视觉效果好。
- 版本2劣势
- 没有使用 continues 这个值,即不能自定义中间连续页的个数,可复用性差。
版本1(推荐)
思路
- 计算出总共多少页(向上取整(总个数 / 每一页显示的数));
- 根据要求中间显示多少页的个数,来进行计算出中间页的页码数(本例中默认给的参数
continues
[来自props传参]); - 再根据中间页的开始和结尾页码来判定是否显示其前面的部分与后面的部分(见图示);
- 开头处的页码
1
与···
显示,与尾处的显示说明见图;
- 京东显示图示。
参数说明(来源父传子)
props: ["pageNo", "pageSize", "total", "continues"],
pageNo
当前显示的页码数;pageSize
每一页能显示多少个;total
共多少条数据;continues
中间页(连续部分)页码要求是多少个(本例中为5)。
完整代码
<template>
<div class="pagination">
<!-- 如果 选择页 pageNo 为第一页时,则禁止按钮使用 -->
<button :disabled="pageNo == 1">
上一页
</button>
<!-- 如果 计算结果startNumAndEndNum.start > 1,意味着中间部分的页码数是从2及以上开始显示的,则需要显示1 -->
<!-- 因为如果pageNo(当前页)为1、2、3时算出来的start都为1,则pageNo=4时,才会显示 -->
<button
v-if="startNumAndEndNum.start > 1"
@click="$emit('update:pageNo', 1)"
:class="{ active: pageNo == 1 }"
>
1
</button>
<!-- 当start > 2时,即最小为start = 3时显示...(这里个人觉得不严谨:如果为3时应该显示2;不过京东也是这样显示的[见说明图]) -->
<button v-if="startNumAndEndNum.start > 2">···</button>
<!-- 中间部分 -->
<!-- 遍历最大的值会生成数组,比如end是9,则为[1, 2, 3, 4, 5, 6, 7, 8, 9] -->
<!-- 此时我们只需要保留大于等于 start的值的部分即可,即[5, 6, 7, 8, 9] -->
<button
v-for="(page, index) in startNumAndEndNum.end"
:key="index"
v-if="page >= startNumAndEndNum.start"
@click="$emit('update:pageNo', page)"
:class="{ active: pageNo == page }"
>
{{ page }}
</button>
<!-- 下 -->
<button v-if="startNumAndEndNum.end < totalPage - 1">···</button>
<button
v-if="startNumAndEndNum.end < totalPage"
@click="$emit('update:pageNo', totalPage)"
:class="{active:pageNo==totalPage}"
>
{{ totalPage }}
</button>
<button
:disabled="pageNo == totalPage"
@click="$emit('update:pageNo', pageNo + 1)"
>
下一页
</button>
<button style="margin-left: 30px">共 {{ total }} 条</button>
<!-- <el-empty description="描述文字aaaaaaaaaa"/> -->
</div>
</template>
<script>
export default {
name: "Pagination",
props: ["pageNo", "pageSize", "total", "continues"],
computed: {
//总共多少页
totalPage() {
//向上取证
return Math.ceil(this.total / this.pageSize);
},
//计算出连续的页码的起始数字与结束数字[连续页码的数字:至少是5]
startNumAndEndNum() {
const { continues, pageNo, totalPage } = this;
//先定义两个变量存储起始数字与结束数字
let start = 0,
end = 0;
//连续页码数字5【就是至少五页】,如果出现不正常的现象【就是不够五页】
//不正常现象【总页数没有连续页码多】
if (continues > totalPage) {
start = 1;
end = totalPage;
} else {
//正常现象【连续页码5,但是你的总页数一定是大于5的】
//起始数字
start = pageNo - parseInt(continues / 2);
//结束数字
end = pageNo + parseInt(continues / 2);
//把出现不正常的现象【start数字出现0|负数】纠正
// 因为pageNo可能比较小,出现负数
if (start < 1) {
start = 1;
end = continues;
}
//把出现不正常的现象[end数字大于总页码]纠正
if (end > totalPage) {
end = totalPage;
start = totalPage - continues + 1;
}
}
return { start, end };
},
},
};
</script>
<style lang="less" scoped>
.pagination {
text-align: center;
button {
margin: 0 5px;
background-color: #f4f4f5;
color: #606266;
outline: none;
border-radius: 2px;
padding: 0 4px;
vertical-align: top;
display: inline-block;
font-size: 13px;
min-width: 35.5px;
height: 28px;
line-height: 28px;
cursor: pointer;
box-sizing: border-box;
text-align: center;
border: 0;
&[disabled] {
color: #c0c4cc;
cursor: not-allowed;
}
&.active {
cursor: not-allowed;
background-color: #409eff;
color: #fff;
}
}
}
.active{
background: skyblue;
}
</style>
版本2(自写)
思路
- 计算出总共多少页(向上取整(总个数 / 每一页显示的数));
- 根据要求中间显示多少页的个数,来进行计算出中间页的页码数(本例中默认给的参数
continues
[来自props传参]),分几种情况来判定即可; - 总长度在【3 - 7】之间;
- 总长度等于【8 或 9】或 总长度大于9但所选页码【<= 5】时(这里应该也是属于下面一点的情况之一,但是其中间连续页显示的结果与此条一致,所以放在这里讨论);
- 其余都是考虑总长度大于9的:
- 总长度大于9,所选页码【5 < pageNo < (len - 4)】;
- 总长度大于9,所选页码【pageNo >= (len - 4)】。
- 再处理尾部的两个分页器显示即可(具体见代码)。
- 图示
参数说明(来源父传子)
props: ["pageNo", "pageSize", "total", "continues"],
pageNo
当前显示的页码数;pageSize
每一页能显示多少个;total
共多少条数据;continues
中间页(连续部分)页码要求是多少个(本例中为5,且不能更改)。
完整代码
<template>
<div class="pagination" v-show="needShowPag" @click="handleShow($event)">
<button>上一页</button>
<!-- 如果显示则肯定是显示2页及以上,所以前两个不用判断 -->
<button :class="{ active: pageNo === 1 }">1</button>
<button
:class="{ active: pageNo === 2 }"
:disabled="typeof secondPagShow !== 'number'"
>
{{ secondPagShow }}
</button>
<button
:class="{ active: pageNo === pag }"
v-for="(pag, index) in middlePagShow"
:key="index"
>
{{ pag }}
</button>
<button
:class="{ active: pageNo === penultimatePagShow }"
v-if="penultimatePagShow"
:disabled="typeof penultimatePagShow !== 'number'"
>
{{ penultimatePagShow }}
</button>
<button :class="{ active: pageNo === endPagShow }" v-if="endPagShow">
{{ endPagShow }}
</button>
<button>下一页</button>
<button style="margin-left: 30px">共 {{ totalData }} 条</button>
</div>
</template>
<script>
export default {
name: "Pagination",
props: {
totalData: Number,
continues: Number,
// 以下两个props通过sync修饰符的方式来传递的
pageNo: Number,
pageSize: Number,
},
data() {
return {
pagLength: 0, // 整个页码的长度
};
},
computed: {
// 是否需要展示分页器(需要展示的总数据 > 分页的数据)
needShowPag() {
return this.totalData > this.pageSize;
},
// 处理第二页分页情况
secondPagShow() {
let len = this.pagLength;
// 如果长度在3-9之间的话,本来就能能显示9个,则显示页码2的概率为100%;
if (len >= 3 && len <= 9) {
return 2;
} else {
//! 总的超过9页了,那么肯定会有 (•••) 显示;
//! 当前选择的页码数 > 3时, 2号位100%显示(•••)
console.log("second");
return this.pageNo > 3 ? "•••" : 2;
}
},
// 处理中间页
middlePagShow() {
let len = this.pagLength;
// 上来先置空
let pagAry = []; // 存放中间页码的
// 最多存放5位,并且总页面数如果在3-9之间都是存放[3, 4, 5, 6, 7]这几个数
console.log("init", len, this.pageNo);
if (len >= 3 && len <= 7) {
for (let pag = 3; pag <= len; pag++) {
pagAry.push(pag);
}
} else if ([8, 9].includes(len) || (len > 9 && this.pageNo <= 5)) {
pagAry = [3, 4, 5, 6, 7];
} else if (len > 9 && this.pageNo > 5 && this.pageNo < len - 4) {
//! 最后至少要有4位空余(尾号2位,中间5位数组的后两位),则为len-4
// 所选位置(中间位置为this.pageNo,则取前后各两位,组成5位数的数组)
/* for (let pag = this.pageNo - 2; pag <= this.pageNo + 3; pag++) {
pagAry.push(pag);
} */
pagAry = [
this.pageNo - 2,
this.pageNo - 1,
this.pageNo,
this.pageNo + 1,
this.pageNo + 2,
];
} else if (len > 9 && this.pageNo >= len - 4) {
console.log("last");
for (let pag = len - 6; pag <= len - 2; pag++) {
pagAry.push(pag);
}
// pagAry = [len - 6, len - 5, len - 4, len - 3, len - 2];
}
return pagAry;
},
// 处理 倒数 第二个分页情况
penultimatePagShow() {
let len = this.pagLength;
// 如果长度在3-9之间的话,本来就能能显示9个,则显示页码2的概率为100%;
if (len === (8 || 9)) {
return 8;
} else if (len > 9) {
//! 总的超过9页了,那么肯定会有 (•••) 显示;
//! 当前选择的页码数 > 总数 - 5 时,则意味着一定显示的是倒数第二个数值
return this.pageNo > len - 5 ? len - 1 : "•••";
} else {
// 如果总数都在8以下,则不显示
return 0;
}
},
// 处理 最后一个 分页情况
endPagShow() {
let len = this.pagLength;
// 如果长度在3-9之间的话,本来就能能显示9个,则显示页码2的概率为100%;
if (len === 8) {
return 0;
} else if (len >= 9) {
//! 总的超过9页了,那么肯定会有 (•••) 显示;
//! 当前选择的页码数 > 总数 - 5 时,则意味着一定显示的是倒数第二个数值
return len;
}
},
},
methods: {
// 处理点击事件
handleShow(ev) {
if (ev.target.tagName.toLowerCase() === "button") {
// 如果点击的是数字分页器按钮(不含...的)
if (ev.target.innerText.match(/^\d+$/)) {
let clickNum = ev.target.innerText.match(/^\d+$/)[0];
console.log("点击的是:数字分页器", clickNum);
// this.pageNo = clickNum;
// 自定义事件方式
// this.$emit('changePageNo', Number(clickNum));
// 使用 sync 修饰符的方式.
this.$emit("update:pageNo", Number(clickNum));
}
}
},
},
watch: {
// 如果totalData数据变了,则自身的pagLength也会变
totalData: {
immediate: true,
handler(newValue) {
// 向上取整
this.pagLength = Math.ceil(newValue / this.pageSize);
console.log(this.pagLength);
},
},
},
};
</script>
<style lang="less" scoped>
.pagination {
text-align: center;
button {
margin: 0 5px;
background-color: #f4f4f5;
color: #606266;
outline: none;
border-radius: 2px;
padding: 0 4px;
vertical-align: top;
display: inline-block;
font-size: 13px;
min-width: 35.5px;
height: 28px;
line-height: 28px;
cursor: pointer;
box-sizing: border-box;
text-align: center;
border: 0;
&[disabled] {
// color: #c0c4cc;
background-color: #ffffff;
cursor: not-allowed;
border: none;
}
&.active {
// cursor: not-allowed;
background-color: #409eff;
color: #fff;
}
}
}
</style>