refactor: pagination component

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/628/head
Ryan Wang 2022-09-29 12:47:03 +08:00
parent c4056c5b72
commit 668c678714
8 changed files with 96 additions and 66 deletions

View File

@ -2,8 +2,8 @@
<Story :init-state="initState" title="Pagination"> <Story :init-state="initState" title="Pagination">
<template #default="{ state }"> <template #default="{ state }">
<VPagination <VPagination
:page="state.page" v-model:page="state.page"
:size="state.size" v-model:size="state.size"
:total="state.total" :total="state.total"
></VPagination> ></VPagination>
</template> </template>

View File

@ -1,24 +1,32 @@
<script lang="ts" setup> <script lang="ts" setup>
import { UseOffsetPagination } from "@vueuse/components";
import { IconArrowLeft, IconArrowRight } from "../../icons/icons"; import { IconArrowLeft, IconArrowRight } from "../../icons/icons";
import { ref, toRefs, watch } from "vue"; import { ref, toRefs, watch, watchEffect } from "vue";
import { useOffsetPagination } from "@vueuse/core";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
page?: number; page?: number;
size?: number; size?: number;
total?: number; total?: number;
sizeOptions?: number[];
}>(), }>(),
{ {
page: 1, page: 1,
size: 10, size: 10,
total: 0, total: 0,
sizeOptions: () => [10],
} }
); );
const { page, size, total } = toRefs(props); const page = ref(props.page);
const size = ref(props.size);
const total = ref(props.total);
const key = ref(Math.random()); watch([() => props.page, () => props.size, () => props.total], () => {
page.value = props.page;
size.value = props.size;
total.value = props.total;
});
const emit = defineEmits<{ const emit = defineEmits<{
(event: "update:page", page: number): void; (event: "update:page", page: number): void;
@ -33,81 +41,97 @@ const onPageChange = ({
currentPage: number; currentPage: number;
currentPageSize: number; currentPageSize: number;
}) => { }) => {
emit("update:page", currentPage);
emit("update:size", currentPageSize);
emit("change", { emit("change", {
page: currentPage, page: currentPage,
size: currentPageSize, size: currentPageSize,
}); });
}; };
watch( const {
() => total?.value, currentPage,
() => { currentPageSize,
key.value = Math.random(); pageCount,
} isFirstPage,
); isLastPage,
prev,
next,
} = useOffsetPagination({
total: total,
page: page,
pageSize: size,
onPageChange: onPageChange,
onPageSizeChange: onPageChange,
});
</script> </script>
<template> <template>
<UseOffsetPagination <div class="bg-white flex items-center justify-between">
:key="key" <div class="flex-1 flex justify-between sm:!hidden items-center">
v-slot="{ currentPage, next, prev, pageCount }" <span
:page="page" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
:page-size="size" @click="prev"
:total="total" >
@page-change="onPageChange" <IconArrowLeft />
@page-size-change="onPageChange" </span>
> <span class="text-sm text-gray-500">
<div class="bg-white flex items-center justify-between"> {{ currentPage }} / {{ pageCount }}
<div class="flex-1 flex justify-between sm:!hidden items-center"> </span>
<span <span
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer" class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
@click="next"
>
<IconArrowRight />
</span>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center items-center gap-2">
<nav
aria-label="Pagination"
class="relative z-0 inline-flex rounded-base shadow-sm -space-x-px"
>
<button
class="relative h-8 outline-none inline-flex items-center px-2 py-1.5 rounded-l-base border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer disabled:cursor-not-allowed"
:disabled="isFirstPage"
@click="prev" @click="prev"
> >
<IconArrowLeft /> <IconArrowLeft />
</span> </button>
<span class="text-sm text-gray-500"> <button
{{ currentPage }} / {{ pageCount }} class="relative h-8 outline-none inline-flex items-center px-2 py-1.5 rounded-r-base border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer disabled:cursor-not-allowed"
</span> :disabled="isLastPage"
<span
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 cursor-pointer"
@click="next" @click="next"
> >
<IconArrowRight /> <IconArrowRight />
</span> </button>
</div> </nav>
<div class="hidden sm:flex-1 sm:flex sm:items-center"> <div class="inline-flex items-center gap-2">
<nav <select
aria-label="Pagination" v-model="currentPage"
class="relative z-0 inline-flex rounded-base shadow-sm -space-x-px" :disabled="pageCount === 0"
class="h-8 border outline-none rounded-base px-2 text-gray-800 text-sm border-gray-300"
> >
<span <option v-if="pageCount === 0" :value="0">0 / 0</option>
class="relative inline-flex items-center px-2 py-2 rounded-l-[4px] border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer" <option v-for="i in pageCount" :key="i" :value="i">
@click="prev" {{ i }} / {{ pageCount }}
</option>
</select>
<span class="text-sm text-gray-500"></span>
</div>
<div class="inline-flex items-center gap-2">
<select
v-model="currentPageSize"
class="h-8 border outline-none rounded-base px-2 text-gray-800 text-sm border-gray-300"
>
<option
v-for="(sizeOption, index) in sizeOptions"
:key="index"
:value="sizeOption"
> >
<IconArrowLeft /> {{ sizeOption }}
</span> </option>
<span </select>
v-for="i in pageCount" <span class="text-sm text-gray-500"> / </span>
:key="i"
:class="{
'z-10 bg-primary/1 border-primary text-primary':
i === currentPage,
'bg-white border-gray-300 text-gray-500 hover:bg-gray-50':
i !== currentPage,
}"
aria-current="page"
class="relative inline-flex items-center px-4 py-2 border text-sm font-medium cursor-pointer select-none"
@click="currentPage.value = i"
>
{{ i }}
</span>
<span
class="relative inline-flex items-center px-2 py-2 rounded-r-[4px] border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer"
@click="next"
>
<IconArrowRight />
</span>
</nav>
</div> </div>
</div> </div>
</UseOffsetPagination> </div>
</template> </template>

View File

@ -690,6 +690,7 @@ onMounted(() => {
:page="attachments.page" :page="attachments.page"
:size="attachments.size" :size="attachments.size"
:total="attachments.total" :total="attachments.total"
:size-options="[60, 120, 200]"
@change="handlePaginationChange" @change="handlePaginationChange"
/> />
</div> </div>

View File

@ -165,6 +165,7 @@ await handleFetchAttachments();
:page="attachments.page" :page="attachments.page"
:size="attachments.size" :size="attachments.size"
:total="attachments.total" :total="attachments.total"
:size-options="[60, 120, 200]"
@change="handlePaginationChange" @change="handlePaginationChange"
/> />
</div> </div>

View File

@ -428,6 +428,7 @@ function handleSelectUser(user: User | undefined) {
:page="comments.page" :page="comments.page"
:size="comments.size" :size="comments.size"
:total="comments.total" :total="comments.total"
:size-options="[20, 30, 50, 100]"
@change="handlePaginationChange" @change="handlePaginationChange"
/> />
</div> </div>

View File

@ -638,6 +638,7 @@ function handleSortItemChange(sortItem?: SortItem) {
:page="singlePages.page" :page="singlePages.page"
:size="singlePages.size" :size="singlePages.size"
:total="singlePages.total" :total="singlePages.total"
:size-options="[20, 30, 50, 100]"
@change="handlePaginationChange" @change="handlePaginationChange"
/> />
</div> </div>

View File

@ -928,6 +928,7 @@ function handleContributorChange(user?: User) {
:page="posts.page" :page="posts.page"
:size="posts.size" :size="posts.size"
:total="posts.total" :total="posts.total"
:size-options="[20, 30, 50, 100]"
@change="handlePaginationChange" @change="handlePaginationChange"
/> />
</div> </div>

View File

@ -36,7 +36,7 @@ const grantPermissionModal = ref<boolean>(false);
const users = ref<UserList>({ const users = ref<UserList>({
page: 1, page: 1,
size: 10, size: 20,
total: 0, total: 0,
items: [], items: [],
first: true, first: true,
@ -486,6 +486,7 @@ onMounted(() => {
:page="users.page" :page="users.page"
:size="users.size" :size="users.size"
:total="users.total" :total="users.total"
:size-options="[20, 30, 50, 100]"
@change="handlePaginationChange" @change="handlePaginationChange"
/> />
</div> </div>