136 lines
3 KiB
Vue
136 lines
3 KiB
Vue
<script setup lang="ts">
|
||
import { computed, defineProps } from "vue";
|
||
|
||
const props = defineProps({
|
||
page: {
|
||
type: Number,
|
||
required: true,
|
||
},
|
||
itemsPerPage: {
|
||
type: Number,
|
||
required: true,
|
||
},
|
||
totalItems: {
|
||
type: Number,
|
||
required: true,
|
||
},
|
||
});
|
||
|
||
const firstItem = computed(() => {
|
||
return Math.min(
|
||
props.totalItems,
|
||
(props.page - 1) * props.itemsPerPage + 1
|
||
);
|
||
});
|
||
const lastItem = computed(() =>
|
||
Math.min(props.totalItems, firstItem.value + props.itemsPerPage - 1)
|
||
);
|
||
const lastPage = computed(() =>
|
||
Math.ceil(props.totalItems / props.itemsPerPage)
|
||
);
|
||
const pages = computed(() => {
|
||
const pages: number[] = [];
|
||
if (lastPage.value <= 2) {
|
||
return pages;
|
||
}
|
||
|
||
let p1 = props.page - 1;
|
||
if (props.page === lastPage.value) {
|
||
p1 = props.page - 2;
|
||
}
|
||
if (p1 <= 1) {
|
||
p1 = 2;
|
||
}
|
||
|
||
for (let p = p1; p <= p1 + 2; p += 1) {
|
||
if (p < lastPage.value) {
|
||
pages.push(p);
|
||
}
|
||
}
|
||
|
||
return pages;
|
||
});
|
||
|
||
const showFirstEllipsis = computed(
|
||
() => pages.value.length > 0 && pages.value[0] > 2
|
||
);
|
||
const showLastEllipsis = computed(
|
||
() =>
|
||
pages.value.length > 0 &&
|
||
pages.value[pages.value.length - 1] < lastPage.value - 1
|
||
);
|
||
|
||
const emit = defineEmits<{
|
||
(e: "changePage", page: number): void;
|
||
}>();
|
||
|
||
function toPage(page: number): void {
|
||
emit("changePage", page);
|
||
}
|
||
|
||
// noinspection JSIncompatibleTypesComparison
|
||
const classes = computed(
|
||
() => (p: number) => p === props.page ? ["current-page"] : []
|
||
);
|
||
</script>
|
||
|
||
<template>
|
||
<nav>
|
||
<span class="total">
|
||
<strong>{{ firstItem }}</strong>
|
||
-
|
||
<strong>{{ lastItem }}</strong>
|
||
von
|
||
<strong>{{ totalItems }}</strong>
|
||
</span>
|
||
|
||
<ul>
|
||
<li v-if="page > 1" @click="toPage(page - 1)">‹</li>
|
||
<li :class="classes(1)" @click="toPage(1)">1</li>
|
||
<li v-if="showFirstEllipsis" class="ellipsis">…</li>
|
||
<li
|
||
v-for="page in pages"
|
||
v-bind:key="page"
|
||
:class="classes(page)"
|
||
@click="toPage(page)"
|
||
>
|
||
{{ page }}
|
||
</li>
|
||
<li v-if="showLastEllipsis" class="ellipsis">…</li>
|
||
<li
|
||
v-if="lastPage > 1"
|
||
:class="classes(lastPage)"
|
||
@click="toPage(lastPage)"
|
||
>
|
||
{{ lastPage }}
|
||
</li>
|
||
<li v-if="page < lastPage" @click="toPage(page + 1)">›</li>
|
||
</ul>
|
||
</nav>
|
||
</template>
|
||
|
||
<style lang="scss" scoped>
|
||
@import "../scss/variables";
|
||
|
||
ul {
|
||
display: inline-block;
|
||
list-style: none;
|
||
|
||
li {
|
||
display: inline-block;
|
||
min-width: 2em;
|
||
height: 1.5em;
|
||
line-height: 1.5em;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
|
||
&.current-page {
|
||
color: $variant-color-info;
|
||
}
|
||
|
||
&.ellipsis {
|
||
cursor: initial;
|
||
}
|
||
}
|
||
}
|
||
</style>
|