usePagination Composable
Reactive pagination logic with page size control and range calculation
Code
import { ref, computed, type Ref } from 'vue';
export function usePagination<T>(
items: Ref<T[]>,
options: {
initialPage?: number;
initialPageSize?: number;
maxPageNumbers?: number;
} = { initialPage: 1, initialPageSize: 10, maxPageNumbers: 5 }
) {
const currentPage = ref(options.initialPage ?? 1);
const pageSize = ref(options.initialPageSize ?? 10);
const maxPageNumbers = ref(options.maxPageNumbers ?? 5);
// Total items count
const totalItems = computed(() => items.value.length);
// Total pages count
const totalPages = computed(() => {
return Math.ceil(totalItems.value / pageSize.value);
});
// Current page items
const paginatedItems = computed(() => {
const startIndex = (currentPage.value - 1) * pageSize.value;
const endIndex = startIndex + pageSize.value;
return items.value.slice(startIndex, endIndex);
});
// Page numbers to display (for pagination UI)
const pageNumbers = computed(() => {
const pages: number[] = [];
const total = totalPages.value;
const current = currentPage.value;
const max = maxPageNumbers.value;
__TOKEN_36__ (total <= max) {
// Show all pages
__TOKEN_37__ (let i = 1; i <= total; i++) {
pages.push(i);
}
} else {
// Calculate range around current page
const half = Math.floor(max / 2);
let start = Math.max(1, current - half);
let end = Math.min(total, current + half);
// Adjust if near start/end
__TOKEN_43__ (end - start + 1 < max) {
__TOKEN_44__ (start === 1) {
end = Math.min(total, start + max - 1);
} else __TOKEN_46__ (end === total) {
start = Math.max(1, end - max + 1);
}
}
__TOKEN_47__ (let i = start; i <= end; i++) {
pages.push(i);
}
// Add ellipsis markers
__TOKEN_49__ (start > 1) {
pages.unshift(-1); // Ellipsis marker
pages.unshift(1);
}
__TOKEN_50__ (end < total) {
pages.push(-1); // Ellipsis marker
pages.push(total);
}
}
return pages;
});
// Navigation methods
const goToPage = (page: number) => {
__TOKEN_53__ (page < 1 || page > totalPages.value) return;
currentPage.value = page;
};
const nextPage = () => {
__TOKEN_56__ (currentPage.value < totalPages.value) {
currentPage.value++;
}
};
const prevPage = () => {
__TOKEN_58__ (currentPage.value > 1) {
currentPage.value--;
}
};
const firstPage = () => {
currentPage.value = 1;
};
const lastPage = () => {
currentPage.value = totalPages.value;
};
const setPageSize = (size: number) => {
pageSize.value = size;
// Reset to first page when changing page size
currentPage.value = 1;
};
return {
currentPage,
pageSize,
totalItems,
totalPages,
paginatedItems,
pageNumbers,
goToPage,
nextPage,
prevPage,
firstPage,
lastPage,
setPageSize
};
}
// Usage example
// const items = ref(Array.from({ length: 100 }, (_, i) => ({ id: i + 1 })));
// const { paginatedItems, currentPage, goToPage, nextPage } = usePagination(items);