SwPagination

SwPagination is a numbered pager: a controlled v-model:page; when the page changes, the parent replaces the whole list data set (replace-mode) — this and SwGallery's @load-more (append-mode) are two mutually exclusive data flows. Pick one per scenario; don't mix them.

Responsiveness is a pure CSS media-query dual layout: the full desktop version (page-number window + ellipsis + jumper + total) and the simplified mobile version (prev N / M next) are both rendered and toggled by breakpoint (768px, aligned with the framework) — no JS width measuring, no SSR hydration risk.

Basic pagination (page count from total/pageSize + total count text)

加载中...

Combining with SwGallery (numbered-paging scenario)

Grid + pager = a SwGallery with loadMode="none" + this component; replace the whole items set whenever the page changes:

SwGallery (none) + SwPagination combined paging

加载中...
<script setup lang="ts">
const page = ref(1)
const { data } = await useAsyncData(
  () => `list-${page.value}`,
  () => request<MovieList>('/movie/list', { body: { page: page.value, page_size: 24 } }),
  { watch: [page] },
)
</script>

<template>
  <SwGallery :items="data?.list ?? []" load-mode="none">
    <template #default="{ item }">…</template>
  </SwGallery>
  <!-- legacy protocol sends numbers as strings: normalize with a one-line unary + -->
  <SwPagination v-model:page="page" :page-count="+(data?.last_page ?? 1)" :total="+(data?.total ?? 0)" show-total />
</template>

Customization

pageCount passed directly + window 7 + custom arrows + disabled loading lock

加载中...

maxVisible window folding + showTotal

加载中...

disabled loading lock

加载中...

Props

NameTypeRequiredDefaultDescription
page (v-model)number✓—Current page number (1-based, controlled)
totalnumber0Total item count; combined with pageSize to derive the page count
pageSizenumber20Items per page
pageCountnumberundefinedPage count passed directly (backend gives last_page); takes priority over the total-based calculation
maxVisiblenumber5Page-number window width (odd number recommended); overflow collapses into an ellipsis
showJumperbooleantrueDesktop "前往 N 页" (go to page N) jumper input (submit on Enter, out-of-range values are clamped)
showTotalbooleanfalse"共 N 条" (N items in total) text (requires total)
disabledbooleanfalseDisable all interaction (while loading)
ariaLabelstring'分页'aria-label of the <nav> (Chinese for "pagination")

Events

NamePayloadDescription
update:pagepage: numberPage changed (not emitted for same page / out-of-range / disabled)

Slots

NameDescription
prev / nextCustom previous / next content (defaults to inline SVG arrows)

Style Tokens

These CSS variables can be overridden on your side (the fallback is the default):

VariableDefaultDescription
--sw-pagination-gap0.25remGap between page items
--sw-pagination-item-size2remMinimum width/height of one page item (square hit area)
--sw-pagination-item-padding0.375remPage item padding (widens items as the digit count grows)
--sw-pagination-font-size0.875remPage item font size

Caveats

  • Hidden entirely when the page count ≤ 1 (nothing to page through, so nothing renders).
  • Replace-mode vs append-mode: for infinite scroll / load more use SwGallery's loadMode; don't simulate it with page numbers.
  • On ISR pages, carry the page number in the URL (a RESTful path like /list/page/2 or a GET query) so the cache key distinguishes pages — just bind v-model:page to the route param.

See Also