使用Vue3实现一个简单的分页器

810 阅读2分钟

这篇文章主要讲述了使用Vue3实现的一个简单版分页器

pager.gif

分页组件需要的三个参数

参数说明类型
currentPage当前显示页码Number
pageSize当前页面数据量Number
total数据总数Number

template部分:

主要结构分为五个部分

  • 切换上一页按钮
  • 向前折叠按钮
  • 页码按钮
  • 向后折叠按钮
  • 切换下一页按钮
<template>
  <div class="pagination">
    <div
      class="pagination__prev"
      @click="switchPage(-1)"
      :class="{ disabled: current === 1 }"
    >
      <i class="iconfont icon-shouqijiantouxiao"></i>
    </div>
    <ul class="pagination__page">
      <li
        v-if="pageCount > 0"
        @click="current = 1"
        :class="{ active: current === 1 }"
      >
        1
      </li>
      <li
        class="pagination__quickprv more"
        v-if="showPrevMore"
      >
        <i class="iconfont icon-24gf-ellipsis"></i>
      </li>
      <li
        v-for="pager in pagers"
        :key="pager"
        @click="jumpPage(pager)"
        :class="{ active: current === pager }"
      >
        {{ pager }}
      </li>
      <li
        class="pagination__quicknext more"
        v-if="showNextMore"
      >
        <i class="iconfont icon-24gf-ellipsis"></i>
      </li>
      <li
        v-if="pageCount > 1"
        @click="current = pageCount"
        :class="{ active: current === pageCount }"
      >
        {{ pageCount }}
      </li>
    </ul>
    <div
      class="pagination__next"
      :class="{ disabled: current === pageCount }"
    >
      <i
        class="iconfont icon-shouqijiantouxiao"
        @click="switchPage(1)"
      ></i>
    </div>
  </div>
</template>

script部分

props接收父组件传过来的数据,指定每个参数的类型并给予默认值


const props = defineProps({
  //当前页数
  currentPage: {
    type: Number,
    default: 8
  },
  // 当前页面数据数量
  pageSize: {
    type: Number,
    default: 50
  },
  // 数据总数
  total: {
    type: Number,
    default: 1000
  }
})

需要的常量和变量定义

  • 定义当前页码current,从props.currentPage中赋值
  • showPrevMore:是否展示向前折叠图标
  • showNextMore:是否展示向后折叠图标
  • pageCount:数据总量除以当前页面数据量
    1. props中数据总量total默认值为1000
    2. props中当前页面数据量pageSize默认值为50
    3. pageCount计算得到的值为20,如文章置顶的gif演示动图,一共20个页码。
  • pagerCount的值为7,代表分页器上只展示7个按钮,这个常量也可以作为props传入
  • emit的change事件,在点击页码按钮时需要向父级组件传递的事件,比如更新翻页数据
<script setup lang="ts">
import { ref, computed, watchEffect } from "vue"

const current = ref<number>(props.currentPage)
const showPrevMore = ref(false)
const showNextMore = ref(false)
const pageCount = props.total % props.pageSize === 0 ? props.total / props.pageSize : Math.floor(props.total / props.pageSize) + 1
const pagerCount = 7

const emit = defineEmits(["change"])

需要的计算属性和方法

  • 计算属性pagers
    • 主要分为两个步骤:
      1. 判断showPrevMoreshowNextMore的值
      2. 通过showPrevMore和showNextMore的真假值展示页码
  • switchPage方法: 进行左右按钮切换
  • jumpPage方法: 单击页码跳转
const pagers = computed(() => {
  let showPrevMore = false
  let showNextMore = false
  const halfPageCount = (pagerCount - 1) / 2
  if (pageCount > pagerCount) {
    // 如果当前页码 大于 最大页码按钮数 减去 最大页码按钮数的一半则显示 向前 展开按钮
    if (current.value > pagerCount - halfPageCount) {
      showPrevMore = true
    }
    // 如果当前页码 小于 总页码数 减去 最大页码按钮数的一半则显示 向后 展开按钮
    if (current.value < pageCount - halfPageCount) {
      showNextMore = true
    }
  }
  const array: number[] = []
  if (showPrevMore && !showNextMore) {
    // 如果只展示了向前折叠按钮,则按钮值为 最大页面数减去当前页面按钮再减二(减二是因为1和最后一页按钮已经存在存在)
    const startPage = pageCount - (pagerCount - 2)
    for (let i = startPage; i < pageCount; i++) {
      array.push(i)
    }
  } else if (!showPrevMore && showNextMore) {
    // 如果只展示了向后折叠按钮,则按钮值直接从2开始,不大于7(因为页面按钮总数是7)
    for (let i = 2; i < pagerCount; i++) {
      array.push(i)
    }
  } else if (showPrevMore && showNextMore) {
    // 如果向前和向后折叠按钮都展示,则按钮值为当前页码减2,循环直到当前页面加2
    const offset = Math.floor(pagerCount / 2) - 1
    for (let i = current.value - offset; i <= current.value + offset; i++) {
      array.push(i)
    }
  } else {
    // 如果向前和向后折叠按钮都不展示,则按钮值从2开始循环到页面总数为止
    for (let i = 2; i < pageCount; i++) {
      array.push(i)
    }
  }
  return array
})

const switchPage = (value: number) => {
  if (value > 0) {
    current.value += 1
  } else {
    current.value -= 1
  }
  emit("change", current.value)
}

const jumpPage = (page: number) => {
  current.value = page
  emit("change", current.value)
}

监听当前页码变化

watchEffect(() => {
  const halfPageCount = (pagerCount - 1) / 2
  showPrevMore.value = false
  showNextMore.value = false
  if (pageCount > pagerCount) {
    // 如果当前页码 大于 最大页码按钮数 减去 最大页码按钮数的一半则显示向前展开按钮
    if (current.value > pagerCount - halfPageCount) {
      showPrevMore.value = true
    }

    // 如果当前页码 小于 总页码数 减去 最大页码按钮数的一半则显示向后展开按钮
    if (current.value < pageCount - halfPageCount) {
      showNextMore.value = true
    }
  }
})

样式部分

<style lang="scss">
.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 30px;
  &__prev {
    margin-right: 10px;
    i {
      display: inline-block;
      transform: rotate(-90deg);
      color: var(--secondary-color);
    }
  }
  &__next {
    margin-left: 10px;
    i {
      display: inline-block;
      transform: rotate(90deg);
      color: var(--secondary-color);
    }
  }
  &__prev.disabled,
  &__next.disabled {
    cursor: not-allowed;
    pointer-events: none;
    i {
      color: var(--text-color4);
    }
  }
  &__page {
    display: flex;
    align-items: center;
    li {
      font-size: 1.7rem;
      padding: 0 4px;
      min-width: 32px;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      &:hover {
        color: var(--primary-color);
      }
    }
    li.active {
      background-color: var(--primary-color);
      color: var(--color--white);
      border-radius: 10px;
    }
  }
  .more {
    color: var(--primary-color);
    font-size: 1.6rem;
  }
}
</style>