index.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <template>
  2. <div class="page-select">
  3. <el-select v-bind="{ ...$attrs, value: undefined }" v-model="localValue" :filterable="true" :remote="false"
  4. @visible-change="handleVisibleChange" @change="handleInput">
  5. <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
  6. <!-- 分页组件 -->
  7. <div v-if="total > 0" class="brand-pagination">
  8. <div class="custom-pagination">
  9. <span class="page-arrow" :class="{ disabled: currentPage <= 1 }"
  10. @click="currentPage > 1 && handlePageChange(currentPage - 1)">
  11. &lt;
  12. </span>
  13. <template v-for="page in pageNumbers" :key="page">
  14. <span class="page-number" :class="{ active: page === currentPage }" @click="handlePageChange(page)">
  15. {{ page }}
  16. </span>
  17. </template>
  18. <span class="page-arrow" :class="{ disabled: currentPage >= totalPages }"
  19. @click="currentPage < totalPages && handlePageChange(currentPage + 1)">
  20. &gt;
  21. </span>
  22. <span class="total-text">共{{ total }}条</span>
  23. </div>
  24. </div>
  25. </el-select>
  26. </div>
  27. </template>
  28. <script setup name="PageSelect" lang="ts">
  29. import { ref, computed, watch } from 'vue';
  30. const props = defineProps({
  31. modelValue: {
  32. type: [String, Number],
  33. default: undefined
  34. },
  35. options: {
  36. type: Array,
  37. default: () => []
  38. },
  39. total: {
  40. type: Number,
  41. default: 0
  42. },
  43. pageSize: {
  44. type: Number,
  45. default: 10
  46. }
  47. });
  48. const emit = defineEmits(['update:modelValue', 'page-change', 'visible-change']);
  49. const localValue = ref(props.modelValue);
  50. const currentPage = ref(1);
  51. // 监听modelValue变化
  52. watch(
  53. () => props.modelValue,
  54. (newValue) => {
  55. localValue.value = newValue;
  56. },
  57. { immediate: true }
  58. );
  59. // 计算属性:总页数
  60. const totalPages = computed(() => {
  61. return Math.ceil(props.total / props.pageSize);
  62. });
  63. // 计算属性:页码数组
  64. const pageNumbers = computed(() => {
  65. const pages = [];
  66. const total = totalPages.value;
  67. const current = currentPage.value;
  68. // 生成页码,最多显示5个页码
  69. let start = Math.max(1, current - 2);
  70. let end = Math.min(total, start + 4);
  71. // 调整起始页码,确保显示5个页码
  72. if (end - start < 4) {
  73. start = Math.max(1, end - 4);
  74. }
  75. for (let i = start; i <= end; i++) {
  76. pages.push(i);
  77. }
  78. return pages;
  79. });
  80. // 处理输入变化
  81. const handleInput = (value: any) => {
  82. emit('update:modelValue', value);
  83. };
  84. // 处理可见性变化
  85. const handleVisibleChange = (visible: boolean) => {
  86. if (visible) {
  87. currentPage.value = 1;
  88. }
  89. emit('visible-change', visible);
  90. };
  91. // 处理页面切换
  92. const handlePageChange = (page: number) => {
  93. currentPage.value = page;
  94. emit('page-change', page);
  95. };
  96. </script>
  97. <style scoped>
  98. .page-select {
  99. width: 100%;
  100. }
  101. .brand-pagination {
  102. margin-top: 10px;
  103. padding-top: 10px;
  104. border-top: 1px solid #ebeef5;
  105. text-align: center;
  106. }
  107. .custom-pagination {
  108. display: flex;
  109. align-items: center;
  110. justify-content: center;
  111. gap: 10px;
  112. font-size: 14px;
  113. }
  114. .page-arrow {
  115. cursor: pointer;
  116. color: #606266;
  117. user-select: none;
  118. padding: 2px 8px;
  119. transition: color 0.3s;
  120. }
  121. .page-arrow:hover:not(.disabled) {
  122. color: #409eff;
  123. }
  124. .page-arrow.disabled {
  125. color: #c0c4cc;
  126. cursor: not-allowed;
  127. }
  128. .page-number {
  129. cursor: pointer;
  130. color: #606266;
  131. padding: 2px 8px;
  132. transition: all 0.3s;
  133. }
  134. .page-number:hover {
  135. color: #409eff;
  136. }
  137. .page-number.active {
  138. color: #409eff;
  139. font-weight: bold;
  140. }
  141. .total-text {
  142. margin-left: 15px;
  143. font-size: 12px;
  144. color: #909399;
  145. }
  146. </style>