效果图:
新建components/Pagenation.vue
结构:
<template>
<div class="my-pagination">
<a
:class="{disabled: currentPage === 1}"
href="javascript:"
@click="changePage(false)"
>上一页</a>
<a
v-if="currentPage > 4"
:class="{active: currentPage === 1}"
href="javascript:"
@click="changePage(1)"
>{{
1
}}</a>
<span v-if="currentPage > 4">...</span>
<template
v-for="item in list"
:key="item"
>
<a
v-if="(currentPage < pages - 3 && item !== pages-1) || (currentPage > 4 && item !== 3)"
:class="{active: currentPage === item}"
href="javascript:;"
@click="changePage(item)"
>{{
item
}}</a>
<a
v-if="!(currentPage < pages - 3) && !(currentPage > 4)"
:class="{active: currentPage === item}"
href="javascript:;"
@click="changePage(item)"
>{{
item
}}</a>
</template>
<span v-if="currentPage < pages - 3">...</span>
<a
v-if="currentPage < pages - 3"
:class="{active: currentPage === pages}"
href="javascript:;"
@click="changePage(pages)"
>{{ pages }}</a>
<a
:class="{disabled: currentPage === pages}"
href="javascript:"
@click="changePage(true)"
>下一页</a>
</div>
</template>
逻辑:
import {computed, ref, watch} from 'vue';
const props = defineProps<{ total: number, pageSize: number, page?: number }>();
const emits = defineEmits(['change-page']);
// 动态计算中期的页码信息
// 每页的条数
// const pageSize = 8
// 总页数
const pages = computed(() => Math.ceil(props.total / props.pageSize));
// 当前页码
const currentPage = ref(props.page || 1);
watch(() => props.page, (newVal) => {
currentPage.value = newVal;
});
// 动态计算页码列表
const list = computed(() => {
// 当父组件传递total的值发生变化时,计算属性会重新计算
// pages = Math.ceil(props.total / props.pageSize)
const result = [];
// 总页码小于等于5;大于5
if (pages.value <= 5) {
// 总页码小于等于5的情况
for (let i = 1; i <= pages.value; i++) {
result.push(i);
}
} else {
// 总页码大于5
if (currentPage.value <= 2) {
// 左侧临界值
for (let i = 1; i <= 5; i++) {
result.push(i);
}
} else if (currentPage.value >= pages.value - 1) {
// 右侧临界值
for (let i = pages.value - 4; i <= pages.value; i++) {
result.push(i);
}
} else {
// 中间的状态
for (let i = currentPage.value - 2; i <= currentPage.value + 2; i++) {
result.push(i);
}
}
}
return result;
});
// 控制上一页和下一页变化
const changePage = (type: any) => {
if (type === false) {
// 上一页
// 页面是第一页时,禁止点击操作
if (currentPage.value === 1) {
return;
}
if (currentPage.value > 1) {
currentPage.value -= 1;
}
} else if (type === true) {
// 下一页
// 页面是最后页时,禁止点击操作
if (currentPage.value === pages.value) {
return;
}
if (currentPage.value < pages.value) {
currentPage.value += 1;
}
} else {
// 点击页码
currentPage.value = type;
}
emits('change-page', currentPage.value);
};
样式:
.my-pagination {
display: flex;
justify-content: flex-end;
> a {
display: inline-block;
padding: 5px 10px;
text-decoration: none;
color: #666;
border-radius: 4px;
background: #f0f2f5;
margin-right: 10px;
&:hover {
color: #c40000;
}
&.active {
background: #c40000;
color: #fff;
border-color: #c40000;
}
&.disabled {
cursor: not-allowed;
opacity: 0.4;
&:hover {
color: #333;
}
}
}
> span {
margin-right: 10px;
}
}
使用:
<script lang="ts" setup>
import Pagenation from '@/components/Pagenation.vue';
import { getList } from '@/api/home'
import type { HomeListItem, HomeListReq } from '@/typings/home'
const list = ref<HomeListItem[]>([]);
const pageParams = ref<HomeListReq>({
page: 1,
pageSize: 10,
});
const total = ref(0);
// 获取数据
const getData = async () => {
const {data} = await getList(pageParams.value);
list.value = data.records;
total.value = data.total;
}
// 页码改变
const changePage = async (page: number) => {
pageParams.value.page = page;
getData()
};
</script>
<template>
...
<Pagenation
:page="pageParams.page"
:page-size="pageParams.pageSize"
:total="total"
@change-page="changePage"
/>
</template>