index.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <template>
  2. <div class="page-select">
  3. <el-select v-bind="{ ...$attrs, value: undefined }" v-model="localValue" :filterable="true" :remote="true"
  4. :remote-method="onFilterMethod" @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', 'filter-method']);
  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. // 处理筛选输入变化,重置到第1页
  97. const onFilterMethod = (query: string) => {
  98. currentPage.value = 1;
  99. emit('filter-method', query);
  100. };
  101. </script>
  102. <style scoped>
  103. .page-select {
  104. width: 100%;
  105. }
  106. .brand-pagination {
  107. margin-top: 10px;
  108. padding-top: 10px;
  109. border-top: 1px solid #ebeef5;
  110. text-align: center;
  111. }
  112. .custom-pagination {
  113. display: flex;
  114. align-items: center;
  115. justify-content: center;
  116. gap: 10px;
  117. font-size: 14px;
  118. }
  119. .page-arrow {
  120. cursor: pointer;
  121. color: #606266;
  122. user-select: none;
  123. padding: 2px 8px;
  124. transition: color 0.3s;
  125. }
  126. .page-arrow:hover:not(.disabled) {
  127. color: #409eff;
  128. }
  129. .page-arrow.disabled {
  130. color: #c0c4cc;
  131. cursor: not-allowed;
  132. }
  133. .page-number {
  134. cursor: pointer;
  135. color: #606266;
  136. padding: 2px 8px;
  137. transition: all 0.3s;
  138. }
  139. .page-number:hover {
  140. color: #409eff;
  141. }
  142. .page-number.active {
  143. color: #409eff;
  144. font-weight: bold;
  145. }
  146. .total-text {
  147. margin-left: 15px;
  148. font-size: 12px;
  149. color: #909399;
  150. }
  151. </style>