Pagination 分页

带页码的分页组件,支持自定义页码数量、响应式折叠、不同尺寸和全局主题配置。

基于 Radix Vue PaginationBrConfigProvider 实现。

组件特性

  • 📄 完整导航:显示页码、上一页/下一页、首页/末页控件。
  • 👥 自定义邻页数:配置每侧可见的邻页数。
  • 📱 边缘页码:支持显示首页和末页按钮。
  • 📐 响应式折叠:在小屏幕自动折叠页码。
  • 📏 多种尺寸:支持 smmdlg 尺寸规格。
  • 🎨 主题定制:基于 BrConfigProvider 支持全局主题配置和 TailwindCSS 局部覆盖。

基础用法

最基础的分页,通过 v-model:page 绑定当前页码。

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationFirst,
  BrPaginationItem,
  BrPaginationLast,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'

const currentPage = ref(1)
</script>

<template>
  <div class="flex flex-col items-center gap-4">
    <BrPagination v-model:page="currentPage" :total="100" :sibling-count="1" show-edges>
      <BrPaginationContent v-slot="{ items }">
        <BrPaginationFirst />
        <BrPaginationPrevious />

        <template v-for="(page, index) in items" :key="index">
          <BrPaginationItem v-if="page.type === 'page'">
            <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
              {{ page.value }}
            </BrPaginationLink>
          </BrPaginationItem>
          <BrPaginationEllipsis v-else :key="page.type" :index="index" />
        </template>

        <BrPaginationNext />
        <BrPaginationLast />
      </BrPaginationContent>
    </BrPagination>
    <div class="text-sm text-muted-foreground">Current page: {{ currentPage }}</div>
  </div>
</template>

自定义页码数量

通过 sibling-count 属性可以控制当前页码左右两侧显示的页码数量。

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationFirst,
  BrPaginationItem,
  BrPaginationLast,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'

const currentPage = ref(1)
</script>

<template>
  <div class="flex flex-col items-center gap-4">
    <BrPagination v-model:page="currentPage" :total="100" :sibling-count="3" show-edges>
      <BrPaginationContent v-slot="{ items }">
        <BrPaginationFirst />
        <BrPaginationPrevious />

        <template v-for="(page, index) in items" :key="index">
          <BrPaginationItem v-if="page.type === 'page'">
            <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
              {{ page.value }}
            </BrPaginationLink>
          </BrPaginationItem>
          <BrPaginationEllipsis v-else :key="page.type" :index="index" />
        </template>

        <BrPaginationNext />
        <BrPaginationLast />
      </BrPaginationContent>
    </BrPagination>
    <div class="text-sm text-muted-foreground">Sibling count: 3</div>
  </div>
</template>

不同尺寸

支持 xs, sm, md, lg, xl, 2xl 尺寸变体。

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationItem,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'
import type { PaginationSize } from '@breezeui/vue'

const currentPage = ref(1)
const sizes: { label: string; value: PaginationSize }[] = [
  { label: 'Extra Small (xs)', value: 'xs' },
  { label: 'Small (sm)', value: 'sm' },
  { label: 'Medium (md)', value: 'md' },
  { label: 'Large (lg)', value: 'lg' },
  { label: 'Extra Large (xl)', value: 'xl' },
  { label: '2 Extra Large (2xl)', value: '2xl' },
]
</script>

<template>
  <div class="flex flex-col items-center gap-8">
    <div v-for="size in sizes" :key="size.value" class="flex flex-col items-center gap-2">
      <span class="text-sm font-medium text-muted-foreground">{{ size.label }}</span>
      <BrPagination v-model:page="currentPage" :total="50" :size="size.value">
        <BrPaginationContent v-slot="{ items }">
          <BrPaginationPrevious />
          <template v-for="(page, index) in items" :key="index">
            <BrPaginationItem v-if="page.type === 'page'">
              <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
                {{ page.value }}
              </BrPaginationLink>
            </BrPaginationItem>
            <BrPaginationEllipsis v-else :key="page.type" :index="index" />
          </template>
          <BrPaginationNext />
        </BrPaginationContent>
      </BrPagination>
    </div>
  </div>
</template>

响应式折叠分页

结合 @vueuse/coreuseWindowSize 动态控制 sibling-count 实现小屏自动折叠页码。

<script setup lang="ts">
import { ref, computed } from 'vue'
import { useWindowSize } from '@vueuse/core'
import {
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationFirst,
  BrPaginationItem,
  BrPaginationLast,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'

const currentPage = ref(1)
const { width } = useWindowSize()
const responsiveSiblingCount = computed(() => (width.value < 640 ? 0 : 2))
</script>

<template>
  <div class="flex flex-col items-center gap-4">
    <BrPagination v-model:page="currentPage" :total="100" :sibling-count="responsiveSiblingCount" show-edges>
      <BrPaginationContent v-slot="{ items }">
        <BrPaginationFirst />
        <BrPaginationPrevious />

        <template v-for="(page, index) in items" :key="index">
          <BrPaginationItem v-if="page.type === 'page'">
            <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
              {{ page.value }}
            </BrPaginationLink>
          </BrPaginationItem>
          <BrPaginationEllipsis v-else :key="page.type" :index="index" />
        </template>

        <BrPaginationNext />
        <BrPaginationLast />
      </BrPaginationContent>
    </BrPagination>
    <div class="text-sm text-muted-foreground">
      Try resizing the window width (&lt; 640px)
    </div>
  </div>
</template>

主题定制

BrPagination 组件的颜色(主色调、激活色)、圆角和尺寸完全基于 BrConfigProvider 提供的 CSS 变量实现。

<script setup lang="ts">
import { ref } from 'vue'
import {
  BrConfigProvider,
  BrPagination,
  BrPaginationContent,
  BrPaginationEllipsis,
  BrPaginationFirst,
  BrPaginationItem,
  BrPaginationLast,
  BrPaginationLink,
  BrPaginationNext,
  BrPaginationPrevious,
} from '@breezeui/vue'

const currentPage = ref(1)
const customTheme = {
  primary: '#10b981', // Custom active color (Emerald-500)
  radius: 1.5, // Larger border radius
}
</script>

<template>
  <BrConfigProvider :theme="customTheme">
    <div class="flex justify-center p-4 border rounded-lg bg-background">
      <BrPagination v-model:page="currentPage" :total="100" :sibling-count="1" show-edges>
        <BrPaginationContent v-slot="{ items }">
          <BrPaginationFirst />
          <BrPaginationPrevious />

          <template v-for="(page, index) in items" :key="index">
            <BrPaginationItem v-if="page.type === 'page'">
              <BrPaginationLink :value="page.value" :is-active="page.value === currentPage">
                {{ page.value }}
              </BrPaginationLink>
            </BrPaginationItem>
            <BrPaginationEllipsis v-else :key="page.type" :index="index" />
          </template>

          <BrPaginationNext />
          <BrPaginationLast />
        </BrPaginationContent>
      </BrPagination>
    </div>
  </BrConfigProvider>
</template>

你也可以通过 TailwindCSS 局部覆盖:

<BrPaginationLink class="rounded-full border-blue-500 text-blue-500" />

API

BrPagination

属性类型默认值说明
totalnumber-数据总数
page (v-model)number1当前页码
itemsPerPagenumber10每页显示条数
siblingCountnumber1当前页左右两侧显示的页码数量
showEdgesbooleanfalse是否始终显示首尾页码
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl''md'分页按钮尺寸,会覆盖全局配置
属性类型默认值说明
valuenumber-对应页码的值
isActivebooleanfalse是否为激活状态
disabledbooleanfalse是否禁用
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'-尺寸大小

其他子组件

BrPaginationPreviousBrPaginationNextBrPaginationFirstBrPaginationLast 等均支持传递 class 以通过 TailwindCSS 进行样式覆盖。