这篇文章主要讲述了使用Vue3实现的一个简单版分页器
分页组件需要的三个参数
| 参数 | 说明 | 类型 |
|---|---|---|
| currentPage | 当前显示页码 | Number |
| pageSize | 当前页面数据量 | Number |
| total | 数据总数 | Number |
template部分:
主要结构分为五个部分
- 切换上一页按钮
- 向前折叠按钮
- 页码按钮
- 向后折叠按钮
- 切换下一页按钮
<template>
<div class="pagination">
<div
class="pagination__prev"
@click="switchPage(-1)"
:class="{ disabled: current === 1 }"
>
<i class="iconfont icon-shouqijiantouxiao"></i>
</div>
<ul class="pagination__page">
<li
v-if="pageCount > 0"
@click="current = 1"
:class="{ active: current === 1 }"
>
1
</li>
<li
class="pagination__quickprv more"
v-if="showPrevMore"
>
<i class="iconfont icon-24gf-ellipsis"></i>
</li>
<li
v-for="pager in pagers"
:key="pager"
@click="jumpPage(pager)"
:class="{ active: current === pager }"
>
{{ pager }}
</li>
<li
class="pagination__quicknext more"
v-if="showNextMore"
>
<i class="iconfont icon-24gf-ellipsis"></i>
</li>
<li
v-if="pageCount > 1"
@click="current = pageCount"
:class="{ active: current === pageCount }"
>
{{ pageCount }}
</li>
</ul>
<div
class="pagination__next"
:class="{ disabled: current === pageCount }"
>
<i
class="iconfont icon-shouqijiantouxiao"
@click="switchPage(1)"
></i>
</div>
</div>
</template>
script部分
props接收父组件传过来的数据,指定每个参数的类型并给予默认值
const props = defineProps({
//当前页数
currentPage: {
type: Number,
default: 8
},
// 当前页面数据数量
pageSize: {
type: Number,
default: 50
},
// 数据总数
total: {
type: Number,
default: 1000
}
})
需要的常量和变量定义
- 定义当前页码
current,从props.currentPage中赋值 showPrevMore:是否展示向前折叠图标showNextMore:是否展示向后折叠图标pageCount:数据总量除以当前页面数据量- props中数据总量total默认值为1000
- props中当前页面数据量pageSize默认值为50
- pageCount计算得到的值为20,如文章置顶的gif演示动图,一共20个页码。
pagerCount的值为7,代表分页器上只展示7个按钮,这个常量也可以作为props传入- emit的
change事件,在点击页码按钮时需要向父级组件传递的事件,比如更新翻页数据
<script setup lang="ts">
import { ref, computed, watchEffect } from "vue"
const current = ref<number>(props.currentPage)
const showPrevMore = ref(false)
const showNextMore = ref(false)
const pageCount = props.total % props.pageSize === 0 ? props.total / props.pageSize : Math.floor(props.total / props.pageSize) + 1
const pagerCount = 7
const emit = defineEmits(["change"])
需要的计算属性和方法
- 计算属性
pagers- 主要分为两个步骤:
- 判断
showPrevMore和showNextMore的值 - 通过showPrevMore和showNextMore的真假值
展示页码
- 判断
- 主要分为两个步骤:
switchPage方法: 进行左右按钮切换jumpPage方法: 单击页码跳转
const pagers = computed(() => {
let showPrevMore = false
let showNextMore = false
const halfPageCount = (pagerCount - 1) / 2
if (pageCount > pagerCount) {
// 如果当前页码 大于 最大页码按钮数 减去 最大页码按钮数的一半则显示 向前 展开按钮
if (current.value > pagerCount - halfPageCount) {
showPrevMore = true
}
// 如果当前页码 小于 总页码数 减去 最大页码按钮数的一半则显示 向后 展开按钮
if (current.value < pageCount - halfPageCount) {
showNextMore = true
}
}
const array: number[] = []
if (showPrevMore && !showNextMore) {
// 如果只展示了向前折叠按钮,则按钮值为 最大页面数减去当前页面按钮再减二(减二是因为1和最后一页按钮已经存在存在)
const startPage = pageCount - (pagerCount - 2)
for (let i = startPage; i < pageCount; i++) {
array.push(i)
}
} else if (!showPrevMore && showNextMore) {
// 如果只展示了向后折叠按钮,则按钮值直接从2开始,不大于7(因为页面按钮总数是7)
for (let i = 2; i < pagerCount; i++) {
array.push(i)
}
} else if (showPrevMore && showNextMore) {
// 如果向前和向后折叠按钮都展示,则按钮值为当前页码减2,循环直到当前页面加2
const offset = Math.floor(pagerCount / 2) - 1
for (let i = current.value - offset; i <= current.value + offset; i++) {
array.push(i)
}
} else {
// 如果向前和向后折叠按钮都不展示,则按钮值从2开始循环到页面总数为止
for (let i = 2; i < pageCount; i++) {
array.push(i)
}
}
return array
})
const switchPage = (value: number) => {
if (value > 0) {
current.value += 1
} else {
current.value -= 1
}
emit("change", current.value)
}
const jumpPage = (page: number) => {
current.value = page
emit("change", current.value)
}
监听当前页码变化
watchEffect(() => {
const halfPageCount = (pagerCount - 1) / 2
showPrevMore.value = false
showNextMore.value = false
if (pageCount > pagerCount) {
// 如果当前页码 大于 最大页码按钮数 减去 最大页码按钮数的一半则显示向前展开按钮
if (current.value > pagerCount - halfPageCount) {
showPrevMore.value = true
}
// 如果当前页码 小于 总页码数 减去 最大页码按钮数的一半则显示向后展开按钮
if (current.value < pageCount - halfPageCount) {
showNextMore.value = true
}
}
})
样式部分
<style lang="scss">
.pagination {
display: flex;
align-items: center;
justify-content: center;
line-height: 30px;
&__prev {
margin-right: 10px;
i {
display: inline-block;
transform: rotate(-90deg);
color: var(--secondary-color);
}
}
&__next {
margin-left: 10px;
i {
display: inline-block;
transform: rotate(90deg);
color: var(--secondary-color);
}
}
&__prev.disabled,
&__next.disabled {
cursor: not-allowed;
pointer-events: none;
i {
color: var(--text-color4);
}
}
&__page {
display: flex;
align-items: center;
li {
font-size: 1.7rem;
padding: 0 4px;
min-width: 32px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
&:hover {
color: var(--primary-color);
}
}
li.active {
background-color: var(--primary-color);
color: var(--color--white);
border-radius: 10px;
}
}
.more {
color: var(--primary-color);
font-size: 1.6rem;
}
}
</style>