index.vue 3.96 KB
<!--
 * @Date: 2025-11-18 16:17:40
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-11-25 14:48:19
 * @FilePath: /data-table/src/components/PaginationField/index.vue
 * @Description: 分页组件
-->
<template>
  <div class="pagination-field">
    <div class="indicator">第{{ current + 1 }}页 / 共{{ total }}页</div>
    <div class="actions">
      <div class="actionsLeft">
        <van-button
          v-if="showPrev"
          :disabled="prev_disabled_effective || current === 0"
          round
          type="primary"
          class="btn"
          @click="onPrev"
        >{{ prev_label_effective }}</van-button>
      </div>
      <div class="actionsCenter">
        <van-button v-if="showSubmit" round type="primary" class="btn" @click="onSubmit">{{ submitButton.text }}</van-button>
      </div>
      <div class="actionsRight">
        <van-button v-if="showNext" round type="primary" class="btn" @click="onNext">{{ nextLabel }}</van-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
    current: { type: Number, default: 0 },
    total: { type: Number, default: 1 },
    isLast: { type: Boolean, default: false },
    prevLabel: { type: String, default: '上一页' },
    nextLabel: { type: String, default: '下一页' },
    submitButton: { type: Object, default: { text: '提交', back_title: '上一页', is_back: false } },
    prevDisabled: { type: Boolean, default: false },
})

const emit = defineEmits(['prev', 'next', 'submit'])

/**
 * @description 是否显示上一页按钮(最后一页且 is_back 为 false 时不显示)
 * @returns {import('vue').ComputedRef<boolean>}
 */
const showPrev = computed(() => {
    // 非最后一页按原逻辑显示;最后一页由 submitButton.is_back 控制显示与否
    if (!showSubmit.value) return props.current > 0
    return props.current > 0 && props.submitButton?.is_back !== false
})
const showNext = computed(() => props.current < props.total - 1)
const showSubmit = computed(() => props.current === props.total - 1)

/**
 * @description 计算上一页按钮文案(最后一页用提交按钮配置的返回文案)
 * @returns {import('vue').ComputedRef<string>}
 */
const prev_label_effective = computed(() => {
    // 最后一页使用 submitButton.back_title,否则使用外部传入的 prevLabel
    return showSubmit.value ? (props.submitButton?.back_title || props.prevLabel) : props.prevLabel
})

/**
 * @description 计算上一页按钮禁用状态(最后一页用提交按钮配置的 is_back)
 * @returns {import('vue').ComputedRef<boolean>}
 */
const prev_disabled_effective = computed(() => {
    // 最后一页直接使用 submitButton.is_back 替换 prevDisabled;否则使用外部传入的 prevDisabled
    return showSubmit.value ? (!props.submitButton?.is_back ?? props.prevDisabled) : props.prevDisabled
})

const onPrev = () => emit('prev')
const onNext = () => emit('next')
const onSubmit = () => emit('submit')
</script>

<style lang="less" scoped>
.pagination-field {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: #fff;
  padding: 0.75rem 1rem;
  border-top: 1px solid #eaeaea;
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 10;

  .indicator {
    font-size: 0.85rem;
    color: #666;
    margin-bottom: 0.5rem;
  }

    .actions {
        // 三列栅格:左列起始(上一页),中列居中(提交),右列末尾(下一页)
        display: grid;
        width: 100%;
        grid-template-columns: 1fr auto 1fr;
        align-items: start; // 垂直方向顶对齐
        min-height: 44px; // 保障容器高度,按钮靠顶部

        .actionsLeft {
            justify-self: start; // 左对齐到边
        }

        .actionsCenter {
            justify-self: center; // 中间居中
        }

        .actionsRight {
            justify-self: end; // 右对齐到边
        }

        .btn {
            min-width: 6rem;
        }
    }
}
</style>