Generic usePagination composable with page navigation, size control, and auto-reset on data change. PaginationBar renders prev/next with page size selector. Both support i18n.
71 lines
1.5 KiB
TypeScript
71 lines
1.5 KiB
TypeScript
import { ref, computed, watch, type Ref } from 'vue'
|
|
|
|
export interface PaginationOptions {
|
|
pageSize?: number
|
|
}
|
|
|
|
export interface PaginationReturn<T> {
|
|
page: Ref<number>
|
|
pageSize: Ref<number>
|
|
pageCount: Ref<number>
|
|
paginatedItems: Ref<T[]>
|
|
totalItems: Ref<number>
|
|
next: () => void
|
|
prev: () => void
|
|
goTo: (target: number) => void
|
|
setPageSize: (size: number) => void
|
|
}
|
|
|
|
export function usePagination<T>(
|
|
items: Ref<T[]>,
|
|
options: PaginationOptions = {},
|
|
): PaginationReturn<T> {
|
|
const page = ref(1)
|
|
const pageSize = ref(options.pageSize ?? 20)
|
|
|
|
const totalItems = computed(() => items.value.length)
|
|
|
|
const pageCount = computed(() => Math.max(1, Math.ceil(totalItems.value / pageSize.value)))
|
|
|
|
const paginatedItems = computed(() => {
|
|
const start = (page.value - 1) * pageSize.value
|
|
return items.value.slice(start, start + pageSize.value)
|
|
})
|
|
|
|
// Reset to page 1 when source data or page size changes
|
|
watch([items, pageSize], () => {
|
|
page.value = 1
|
|
})
|
|
|
|
function clamp(target: number): number {
|
|
return Math.max(1, Math.min(target, pageCount.value))
|
|
}
|
|
|
|
function goTo(target: number): void {
|
|
page.value = clamp(target)
|
|
}
|
|
|
|
function next(): void {
|
|
goTo(page.value + 1)
|
|
}
|
|
|
|
function prev(): void {
|
|
goTo(page.value - 1)
|
|
}
|
|
|
|
function setPageSize(size: number): void {
|
|
if (size > 0) pageSize.value = size
|
|
}
|
|
|
|
return {
|
|
page,
|
|
pageSize,
|
|
pageCount,
|
|
paginatedItems,
|
|
totalItems,
|
|
next,
|
|
prev,
|
|
goTo,
|
|
setPageSize,
|
|
}
|
|
}
|