分页器是非常常用的功能,网上也有很多开源的组件,但这些分页器组件有时会因为功能太全而不易于二次开发,于是写了个基础分页器留作备用。
组件逻辑
分页逻辑采用仅显示前后较少页码的形式,不显示最大页码,以防止出现大范围跳页,导致页面卡死。
<template>
<div class="m-pagination">
<button type="button" class="m-btn" :disabled="disablePrev" @click="handleClickPrev">上一页</button>
<ul class="m-pager">
<li class="m-pager-item" :class="{'is-active':page===currentPage}" v-for="page in pagers" :key="page"
@click="handleClickPager(page)">{{page}}
</li>
</ul>
<button type="button" class="m-btn" :disabled="disableNext" @click="handleClickNext">下一页
</button>
</div>
</template>
<script setup>
import {defineProps, defineEmits, computed} from "vue";
const props = defineProps({
currentPage: {
type: Number,
validator(value) {
return value > 0 && Number.isInteger(value);
}
},
totalPages: {
type: Number,
validator(value) {
return value > 0;
}
},
pagerCount: {
type: Number,
validator(value) {
return value >= 5 && value <= 11 && value % 2 !== 0;
},
default: 5
}
})
const emit = defineEmits(["current-change", "update:current-page"]);
const pagers = computed(() => {
const {currentPage, totalPages, pagerCount} = props;
const array = [];
let start, end;
if (totalPages <= pagerCount) {
start = 1;
end = totalPages + 1;
} else {
const offset = (pagerCount - 1) / 2;
start = currentPage - offset;
if (start <= 1) {
start = 1;
end = pagerCount + 1;
} else if (start < offset) {
end = start + pagerCount;
} else if (currentPage + offset >= totalPages) {
end = totalPages + 1;
start = end - pagerCount;
} else {
end = currentPage + offset + 1;
}
}
for (let i = start; i < end; i++) {
array.push(i)
}
return array;
})
const disablePrev = computed(() => {
return props.currentPage <= 1
})
const disableNext = computed(() => {
return props.currentPage >= props.totalPages;
})
const handleClickPager = (page) => {
emitter(page);
}
const handleClickPrev = () => {
if (props.currentPage > 1) {
emitter(props.currentPage - 1);
}
}
const handleClickNext = () => {
if (props.currentPage < props.totalPages) {
emitter(props.currentPage + 1);
}
}
const emitter = (page) => {
emit("update:current-page", page);
emit("current-change", page);
}
</script>
<style scoped lang="scss">
.m-pagination {
display: flex;
justify-content: center;
align-items: center;
}
.m-pager {
padding: 0;
margin: 0;
list-style: none;
display: flex;
justify-content: center;
align-items: center;
}
.m-pager-item {
cursor: pointer;
padding: 0 6px;
height: var(--m-pagination-height);
border: solid 1px var(--m-pagination-border-color);
min-width: var(--m-pagination-height);
text-align: center;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
&:not(:last-child) {
margin-right: 10px;
}
&:hover {
border-color: var(--m-pagination-text-color);
}
&.is-active {
background-color: var(--m-pagination-text-color);
color: white;
}
}
.m-btn {
line-height: var(--m-pagination-height);
box-sizing: border-box;
height: var(--m-pagination-height);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
background-color: transparent;
outline: none;
border: solid 1px var(--m-pagination-border-color);
border-radius: 2px;
&:first-child {
margin-right: 10px;
}
&:last-child {
margin-left: 10px;
}
&:not(:disabled) {
&:hover {
border-color: var(--m-pagination-text-color);
color: white;
background-color: var(--m-pagination-text-color);
}
}
&:disabled {
cursor: not-allowed;
}
}
</style>
样式变量
样式变量代码最好放置在全局样式表(如 global.scss
)中,便于在使用到分页器组件的内部进行覆盖。
:root {
--m-pagination-border-color: #ccc;
--m-pagination-text-color: #3396FD;
--m-pagination-height: 32px;
}