2023-10-30 00:14:54 +00:00
|
|
|
|
<script setup lang="ts">
|
2023-11-06 02:22:33 +00:00
|
|
|
|
import { range } from "lodash-es";
|
|
|
|
|
import { computed } from "vue";
|
2023-10-30 00:14:54 +00:00
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
pages: number;
|
2023-11-01 18:45:16 +00:00
|
|
|
|
modelValue: number;
|
2023-10-30 00:14:54 +00:00
|
|
|
|
}>();
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
2023-11-01 18:45:16 +00:00
|
|
|
|
"update:modelValue": [page: number];
|
2023-10-30 00:14:54 +00:00
|
|
|
|
}>();
|
|
|
|
|
|
|
|
|
|
function handleClick(page: number): void {
|
2023-11-01 18:45:16 +00:00
|
|
|
|
emit("update:modelValue", page);
|
2023-10-30 00:14:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-01 18:45:16 +00:00
|
|
|
|
const isPrevDisabled = computed(() => props.modelValue === 0);
|
|
|
|
|
const isNextDisabled = computed(() => props.modelValue === props.pages - 1);
|
2023-11-12 20:07:18 +00:00
|
|
|
|
const pagesFrom = computed(() => Math.max(0, Math.min(props.modelValue - 2, props.pages - 3)));
|
|
|
|
|
const pagesTo = computed(() => Math.min(props.pages - 1, Math.max(props.modelValue + 2, 2)));
|
|
|
|
|
const pageLinks = computed(() => range(pagesFrom.value, pagesTo.value + 1));
|
2023-10-30 00:14:54 +00:00
|
|
|
|
const showEllipsisBefore = computed(() => pagesFrom.value > 0);
|
|
|
|
|
const showEllipsisAfter = computed(() => pagesTo.value < props.pages - 1);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<ul class="pagination justify-content-center">
|
|
|
|
|
<li class="page-item" :class="{ disabled: isPrevDisabled }">
|
|
|
|
|
<a
|
|
|
|
|
:href="isPrevDisabled ? undefined : 'javascript:'"
|
|
|
|
|
class="page-link"
|
|
|
|
|
aria-label="First"
|
|
|
|
|
@click="handleClick(0)"
|
|
|
|
|
>
|
|
|
|
|
<span aria-hidden="true">«</span>
|
|
|
|
|
</a>
|
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
<li class="page-item" :class="{ disabled: isPrevDisabled }">
|
|
|
|
|
<a
|
|
|
|
|
:href="isPrevDisabled ? undefined : 'javascript:'"
|
|
|
|
|
class="page-link"
|
|
|
|
|
aria-label="Previous"
|
2023-11-01 18:45:16 +00:00
|
|
|
|
@click="handleClick(props.modelValue - 1)"
|
2023-10-30 00:14:54 +00:00
|
|
|
|
>
|
|
|
|
|
<span aria-hidden="true">‹</span>
|
|
|
|
|
</a>
|
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
<li v-if="showEllipsisBefore" class="page-item">
|
|
|
|
|
<span class="page-link">…</span>
|
|
|
|
|
</li>
|
|
|
|
|
|
2023-11-01 18:45:16 +00:00
|
|
|
|
<template v-for="page in pageLinks" :key="page">
|
|
|
|
|
<li class="page-item" :class="{ active: page === props.modelValue }">
|
2023-11-12 20:07:18 +00:00
|
|
|
|
<a href="javascript:" class="page-link" @click="handleClick(page)">{{page + 1}}</a>
|
2023-10-30 00:14:54 +00:00
|
|
|
|
</li>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<li v-if="showEllipsisAfter" class="page-item">
|
|
|
|
|
<span class="page-link">…</span>
|
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
<li class="page-item" :class="{ disabled: isNextDisabled }">
|
|
|
|
|
<a
|
|
|
|
|
:href="isNextDisabled ? undefined : 'javascript:'"
|
|
|
|
|
class="page-link"
|
|
|
|
|
aria-label="Next"
|
2023-11-01 18:45:16 +00:00
|
|
|
|
@click="handleClick(props.modelValue + 1)"
|
2023-10-30 00:14:54 +00:00
|
|
|
|
>
|
|
|
|
|
<span aria-hidden="true">›</span>
|
|
|
|
|
</a>
|
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
<li class="page-item" :class="{ disabled: isNextDisabled }">
|
|
|
|
|
<a
|
|
|
|
|
:href="isNextDisabled ? undefined : 'javascript:'"
|
|
|
|
|
class="page-link"
|
|
|
|
|
aria-label="Last"
|
|
|
|
|
@click="handleClick(pages - 1)"
|
|
|
|
|
>
|
|
|
|
|
<span aria-hidden="true">»</span>
|
|
|
|
|
</a>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</template>
|