| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- <template>
- <div class="page-select">
- <el-select v-bind="{ ...$attrs, value: undefined }" v-model="localValue" :filterable="true" :remote="false"
- @visible-change="handleVisibleChange" @change="handleInput">
- <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
- <!-- 分页组件 -->
- <div v-if="total > 0" class="brand-pagination">
- <div class="custom-pagination">
- <span class="page-arrow" :class="{ disabled: currentPage <= 1 }"
- @click="currentPage > 1 && handlePageChange(currentPage - 1)">
- <
- </span>
- <template v-for="page in pageNumbers" :key="page">
- <span class="page-number" :class="{ active: page === currentPage }" @click="handlePageChange(page)">
- {{ page }}
- </span>
- </template>
- <span class="page-arrow" :class="{ disabled: currentPage >= totalPages }"
- @click="currentPage < totalPages && handlePageChange(currentPage + 1)">
- >
- </span>
- <span class="total-text">共{{ total }}条</span>
- </div>
- </div>
- </el-select>
- </div>
- </template>
- <script setup name="PageSelect" lang="ts">
- import { ref, computed, watch } from 'vue';
- const props = defineProps({
- modelValue: {
- type: [String, Number],
- default: undefined
- },
- options: {
- type: Array,
- default: () => []
- },
- total: {
- type: Number,
- default: 0
- },
- pageSize: {
- type: Number,
- default: 10
- }
- });
- const emit = defineEmits(['update:modelValue', 'page-change', 'visible-change']);
- const localValue = ref(props.modelValue);
- const currentPage = ref(1);
- // 监听modelValue变化
- watch(
- () => props.modelValue,
- (newValue) => {
- localValue.value = newValue;
- },
- { immediate: true }
- );
- // 计算属性:总页数
- const totalPages = computed(() => {
- return Math.ceil(props.total / props.pageSize);
- });
- // 计算属性:页码数组
- const pageNumbers = computed(() => {
- const pages = [];
- const total = totalPages.value;
- const current = currentPage.value;
- // 生成页码,最多显示5个页码
- let start = Math.max(1, current - 2);
- let end = Math.min(total, start + 4);
- // 调整起始页码,确保显示5个页码
- if (end - start < 4) {
- start = Math.max(1, end - 4);
- }
- for (let i = start; i <= end; i++) {
- pages.push(i);
- }
- return pages;
- });
- // 处理输入变化
- const handleInput = (value: any) => {
- emit('update:modelValue', value);
- };
- // 处理可见性变化
- const handleVisibleChange = (visible: boolean) => {
- if (visible) {
- currentPage.value = 1;
- }
- emit('visible-change', visible);
- };
- // 处理页面切换
- const handlePageChange = (page: number) => {
- currentPage.value = page;
- emit('page-change', page);
- };
- </script>
- <style scoped>
- .page-select {
- width: 100%;
- }
- .brand-pagination {
- margin-top: 10px;
- padding-top: 10px;
- border-top: 1px solid #ebeef5;
- text-align: center;
- }
- .custom-pagination {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 10px;
- font-size: 14px;
- }
- .page-arrow {
- cursor: pointer;
- color: #606266;
- user-select: none;
- padding: 2px 8px;
- transition: color 0.3s;
- }
- .page-arrow:hover:not(.disabled) {
- color: #409eff;
- }
- .page-arrow.disabled {
- color: #c0c4cc;
- cursor: not-allowed;
- }
- .page-number {
- cursor: pointer;
- color: #606266;
- padding: 2px 8px;
- transition: all 0.3s;
- }
- .page-number:hover {
- color: #409eff;
- }
- .page-number.active {
- color: #409eff;
- font-weight: bold;
- }
- .total-text {
- margin-left: 15px;
- font-size: 12px;
- color: #909399;
- }
- </style>
|