NumberedPagination.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <template>
  2. <div
  3. v-if="pageCount > 1"
  4. class="flex justify-center pt-5 text-xs md:text-base"
  5. >
  6. <nav aria-label="module-nav">
  7. <ul class="flex list-style-none dark:text-gray-200 text-gray-800">
  8. <li class="page-item">
  9. <button
  10. aria-label="Vorhergehende Seite"
  11. class="pagination-button"
  12. :disabled="currentPageIdx == 0"
  13. @click="
  14. () => {
  15. selectPage(Math.max(currentPageIdx - 1, 0));
  16. }
  17. "
  18. >
  19. <font-awesome-icon icon="fa-solid fa-arrow-left" />
  20. </button>
  21. </li>
  22. <li
  23. v-for="idx in paginationItems"
  24. :key="idx ?? -1"
  25. class="page-item"
  26. :class="[idx == null ? 'flex justify-center items-center' : '']"
  27. >
  28. <span
  29. v-if="idx == null"
  30. class="px-3 md:px-4 text-gray-600 dark:text-gray-400"
  31. >&middot;&middot;&middot;</span
  32. >
  33. <!-- class="cursor-pointer py-1.5 px-3 md:px-4 rounded-sm border-0 outline-hidden transition-all duration-300 hover:bg-gray-200 dark:hover:bg-gray-700 focus:shadow-none" -->
  34. <button
  35. v-else
  36. :title="`Auf die ${idx}. Seite springen`"
  37. class="pagination-button"
  38. :class="[
  39. idx - 1 == currentPageIdx ? 'bg-gray-300 dark:bg-gray-600' : '',
  40. ]"
  41. @click="
  42. () => {
  43. selectPage(idx - 1);
  44. }
  45. "
  46. >
  47. {{ idx }}
  48. </button>
  49. </li>
  50. <li class="page-item">
  51. <button
  52. title="Nächste Seite"
  53. class="pagination-button"
  54. :disabled="currentPageIdx == pageCount - 1"
  55. @click="
  56. () => {
  57. selectPage(Math.min(currentPageIdx + 1, pageCount - 1));
  58. }
  59. "
  60. >
  61. <font-awesome-icon icon="fa-solid fa-arrow-right" />
  62. </button>
  63. </li>
  64. </ul>
  65. </nav>
  66. </div>
  67. </template>
  68. <script lang="ts">
  69. export default {
  70. name: "NumberedPagination",
  71. props: {
  72. pageSize: {
  73. required: true,
  74. type: Number,
  75. },
  76. resultCount: {
  77. required: true,
  78. type: Number,
  79. },
  80. modelValue: {
  81. required: true,
  82. type: Number,
  83. },
  84. },
  85. emits: ["update:modelValue"],
  86. data() {
  87. return {
  88. currentPageIdx: 0,
  89. };
  90. },
  91. computed: {
  92. pageCount() {
  93. return Math.ceil(this.resultCount / this.pageSize);
  94. },
  95. paginationItems() {
  96. const pc = this.pageCount;
  97. if (pc <= 9) {
  98. let pagination = [];
  99. for (let i = 1; i <= pc; i++) pagination.push(i);
  100. return pagination;
  101. }
  102. const cpi = this.currentPageIdx;
  103. if (cpi <= 4) {
  104. return [1, 2, 3, 4, 5, 6, null, pc - 1, pc];
  105. } else if (cpi >= pc - 5) {
  106. return [1, 2, null, pc - 5, pc - 4, pc - 3, pc - 2, pc - 1, pc];
  107. } else {
  108. return [1, 2, null, cpi, cpi + 1, cpi + 2, null, pc - 1, pc];
  109. }
  110. },
  111. },
  112. watch: {
  113. modelValue() {
  114. this.currentPageIdx = this.modelValue;
  115. },
  116. },
  117. methods: {
  118. selectPage(pageIdx: number) {
  119. if (this.currentPageIdx == pageIdx) return;
  120. this.currentPageIdx = pageIdx;
  121. this.$emit("update:modelValue", pageIdx);
  122. },
  123. },
  124. };
  125. </script>
  126. <style scoped>
  127. @reference "../../style.css";
  128. .pagination-button {
  129. @apply cursor-pointer
  130. py-1.5
  131. px-2.5
  132. mx-0.5
  133. md:px-4
  134. rounded-sm
  135. border-0
  136. outline-hidden
  137. transition-all
  138. duration-200
  139. hover:bg-gray-200
  140. active:bg-gray-300
  141. dark:hover:bg-gray-700
  142. dark:active:bg-gray-800
  143. focus:shadow-none;
  144. }
  145. </style>