GrPagination
Берут, когда список не помещается на экран.
Обзор
Когда брать
- список не помещается на экран — номера страниц с усечением середины;
- пользователь выбирает размер страницы —
showPageSizeс набором изpageSizes; - нужно знать объём —
showTotalпечатает «41–60 из 137» рядом с навигацией; - места мало —
compactзаменяет номера индикатором «текущая / всего»; - страниц много —
showJumperдаёт переход по номеру вместо перебора.
Когда взять другое
| Нужно | Берите |
|---|---|
| Список подгружается прокруткой | GrList с virtual и source |
| Строк мало и все помещаются | GrTable |
| Переключаются разделы, а не страницы данных | GrTabs |
| Нужно показать ход длинной операции | GrProgressBar |
page, pageSize и total приходят снаружи: компонент только просит их
изменить. Он ничего не знает про данные и не может знать — их грузит
приложение.
Playground контролы выводятся из API, а не пишутся руками
Загружается…
0 изменено· состояние — в адресе
<GrPagination
:total="137"
:pageSize="10"
:page="3"
size="xs"
:siblingCount="0"
/>Примеры 3 у каждого — живое демо и его код
Таблица заказов со своим подвалом
Компонент берёт итог и размер страницы и вычисляет остальное — число страниц не проп: два источника одной правды расходятся на первом же фильтре.
show-totalотвечает «сколько всего» — слотtotalформулирует это для заказов, —show-page-sizeменяет страницы на прокрутку, аsibling-count="0"держит подвал в одну строку.#4821Tailspin ToysOverdue€217.25#4820Wingtip ToysPaid€180.00#4819Adventure WorksShipped€143.75#4818Northwind TradersRefunded€106.50#4817Contoso LtdOverdue€69.25#4816Fabrikam IncPaid€932.00#4815Tailspin ToysShipped€895.75#4814Wingtip ToysRefunded€858.50#4813Adventure WorksOverdue€821.25#4812Northwind TradersPaid€784.00Журнал аудита на 122 страницы
При 122 страницах номер часто известен — из ссылки в тикете, — поэтому
show-jumperпринимает его сразу: наберите 97 и нажмите Enter. Первая и последняя страницы остаются под рукой вокруг текущей.Audit log2,431 security events of the workspace · newest first 23:57Daniel Kim invited a memberevt_239122:50Grace Wu signed inevt_239021:43Jonas Weber invited a memberevt_238920:36Mina Ortiz signed inevt_238819:29Daniel Kim invited a memberevt_238718:22Grace Wu signed inevt_2386Отзывы на телефоне
На телефоне ряд номеров и не помещается, и не помогает:
compactоставляет стрелки и «3 / 14».Reviews · 4.6 ★ from 42 Grace W. · ★★★★★Bought a second one in navy.
API порождается из пакета · разойтись не может
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
disabled | boolean | undefined | false | Гасит всю пагинацию: номера, кнопки, селект размера и поле перехода. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | Высота кнопок, поля перехода и селекта по шкале контролов. Не задан — из `GrConfigProvider`, иначе `md`. |
ariaLabel | string | undefined | undefined | Имя навигационного лендмарка. По умолчанию — `gr.pagination.label`; задавать стоит там, где пагинаций на странице несколько и их надо различать. |
compact | boolean | undefined | false | Компактный вариант: вместо нумерованных страниц показывается индикатор «текущая / всего» — удобно для узких мест (мобайл, тулбары таблиц). |
pageSizes | GrPaginationPageSizeOption[] | undefined | [10, 20, 50] | Варианты размера страницы. Число — подпись равна значению; пара — своя подпись при том же значении («50 / стр.»), которую иначе было не собрать. |
siblingCount | number | undefined | 1 | Сколько соседних страниц показывать вокруг текущей. По умолчанию `1`. |
boundaryCount | number | undefined | 1 | Сколько крайних страниц всегда показывать с каждого края. По умолчанию `1`. |
showJumper | boolean | undefined | false | Показывать поле «перейти к странице» с быстрым переходом по вводу номера. |
showPageSize | boolean | undefined | false | Показывать селект размера страницы. |
showTotal | boolean | undefined | false | Показывать диапазон показанных элементов — «1–20 из 137». Слот `#total` сильнее. |
jumperLabel | string | undefined | undefined | i18n-подпись перед полем перехода. По умолчанию — `gr.pagination.jumpTo`. |
pageобязательныйv-model | number | — | Текущая страница с единицы (`v-model:page`). Вне диапазона рисуется прижатой к краю. |
pageSizeобязательныйv-model | number | — | Элементов на странице (`v-model:pageSize`) — делитель для числа страниц и диапазона. |
totalобязательный | number | — | Сколько элементов всего, а не страниц: число страниц считается из него и `pageSize`. |
Слоты
| Slot | Type | Описание |
|---|---|---|
total | { from: number; to: number; total: number; } | Диапазон показанных элементов целиком — вместо строки из локали. |
События
| Event | Сигнатура | Описание |
|---|---|---|
update:page | (event: "update:page", value: number): void | — |
update:pageSize | (event: "update:pageSize", value: number): void | — |
Типы
Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.
import type { GrPaginationPageSizeOption, GrPaginationProps, GrPaginationEmits } from '@feugene/granularity/components/GrPagination'Файлdist/types/components/GrPagination/GrPagination.vue.d.ts
Вариант размера страницы: число либо пара «значение + подпись».
Пара нужна там, где подпись не равна числу («50 / стр.», «Все»): собрать её
из голого number[] было нельзя, а обходной путь — свой GrSelect рядом —
терял связь с пагинацией.
type GrPaginationPageSizeOption = number | {
value: number;
label: string;
};interface GrPaginationProps {
/** Текущая страница с единицы (`v-model:page`). Вне диапазона рисуется прижатой к краю. */
page: number;
/** Элементов на странице (`v-model:pageSize`) — делитель для числа страниц и диапазона. */
pageSize: number;
/** Сколько элементов всего, а не страниц: число страниц считается из него и `pageSize`. */
total: number;
/**
* Варианты размера страницы. Число — подпись равна значению; пара — своя
* подпись при том же значении («50 / стр.»), которую иначе было не собрать.
*/
pageSizes?: GrPaginationPageSizeOption[];
/** Сколько соседних страниц показывать вокруг текущей. По умолчанию `1`. */
siblingCount?: number;
/** Сколько крайних страниц всегда показывать с каждого края. По умолчанию `1`. */
boundaryCount?: number;
/**
* Компактный вариант: вместо нумерованных страниц показывается индикатор
* «текущая / всего» — удобно для узких мест (мобайл, тулбары таблиц).
*/
compact?: boolean;
/** Показывать поле «перейти к странице» с быстрым переходом по вводу номера. */
showJumper?: boolean;
/** Показывать селект размера страницы. */
showPageSize?: boolean;
/** Показывать диапазон показанных элементов — «1–20 из 137». Слот `#total` сильнее. */
showTotal?: boolean;
/** i18n-подпись перед полем перехода. По умолчанию — `gr.pagination.jumpTo`. */
jumperLabel?: string;
/**
* Имя навигационного лендмарка. По умолчанию — `gr.pagination.label`; задавать
* стоит там, где пагинаций на странице несколько и их надо различать.
*/
ariaLabel?: string;
/** Гасит всю пагинацию: номера, кнопки, селект размера и поле перехода. */
disabled?: boolean;
/**
* Высота кнопок, поля перехода и селекта по шкале контролов.
* Не задан — из `GrConfigProvider`, иначе `md`.
*/
size?: GrPaginationSize;
}interface GrPaginationEmits {
/**
* Выбрана страница (`v-model:page`). Приходит и сама, когда `total` или `pageSize`
* уменьшились и текущая страница оказалась за последней.
*/
(e: 'update:page', value: number): void;
/**
* Выбран размер страницы в селекте (`v-model:pageSize`).
* На первую страницу компонент не возвращает.
*/
(e: 'update:pageSize', value: number): void;
}Файлdist/types/components/GrPagination/config.d.ts
const grPaginationConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrPagination">;Файлdist/types/components/GrPagination/defaults.d.ts
Пропы GrPagination, настраиваемые глобально через componentDefaults.
interface GrPaginationConfigurableProps {
size: GrComponentSize;
}Файлdist/types/components/GrPagination/grPaginationStyles.d.ts
type GrPaginationSize = GrComponentSize;Файлdist/types/components/GrPagination/safelist.d.ts
const grPaginationSafelist: string[];Доступность
Паттерн APG
—
Клавиши
Enter
| Клавиша | Действие |
|---|---|
| Enter | перейти на введённую страницу |
Полный контракт пакета: docs/keyboard.md ↗
Использование из прозы библиотеки
Контролируемый компонент
page, pageSize и total приходят снаружи, компонент только просит их
изменить:
<GrPagination
v-model:page="page"
v-model:page-size="pageSize"
:total="total"
/>Именно v-model:page, а не v-model: страница — именованная модель, пропа
modelValue у компонента нет. Промах видно по атрибуту modelvalue на корневом
<div> — необъявленный проп уезжает туда через fallthrough; в dev-режиме
компонент дополнительно печатает предупреждение.
Число страниц считается из total и pageSize. Номера усекаются по алгоритму
boundary/sibling: всегда видны первая и последняя страницы плюс siblingCount
соседей вокруг текущей; boundaryCount задаёт, сколько крайних показывать.
Одиночный пропущенный номер рисуется номером, а не многоточием — ряд не прыгает.
Нечисловой вход подменяется дефолтом: не доехавший page даёт первую
страницу, total — ноль, pageSize — единицу, и каждый случай объясняется
предупреждением в dev-режиме. Без этого undefined разошёлся бы по номерам и
статусу как NaN, а разметка осталась бы правдоподобной на вид.
Страница вне диапазона рендерится зажатой к [1, pageCount]: пока родитель
не подтянул значение, активная кнопка всё равно есть. Когда число страниц
уменьшилось (упал total или вырос pageSize), компонент дополнительно эмитит
update:page с последней доступной страницей — если page живёт в URL или
сторе, эта навигация произойдёт сама.
Что показывать
| Проп | Что добавляет |
|---|---|
showPageSize | селект размера страницы; по умолчанию выключен — базовая пагинация это только номера |
pageSizes принимает и числа, и пары «значение + подпись»:
<GrPagination :page-sizes="[10, 20, { value: 50, label: '50 / стр.' }]" show-page-size />Пара нужна там, где подпись не равна числу. Собрать её из голого number[]
было нельзя, а обходной путь — свой GrSelect рядом — терял связь
с пагинацией.
| showTotal | «41–60 из 137» слева от навигации |
| showJumper | поле «перейти к странице»: Enter или уход фокуса применяют номер, выходящий за диапазон — клампится |
| compact | вместо номеров индикатор «текущая / всего» — для мобайла и тулбаров таблиц |
Диапазон целиком заменяется слотом #total — он получает from, to и total:
<GrPagination :total="total" show-total>
<template #total="{ from, to, total }">
Заказы {{ from }}–{{ to }} из {{ total }}
</template>
</GrPagination>disabled гасит всё разом: номера, кнопки, селект и поле перехода.
Перенос на узкой ширине
Ряд пагинации — это четыре группы: итог (showTotal), размер страницы
(showPageSize), навигация и переход (showJumper). Переносится ряд только
между группами. Навигация — первая, назад, страницы, вперёд, последняя — один
неразрывный кластер: «назад» не уезжает на другую строку от своих страниц, а на
узкой ширине кластер уходит на свою строку целиком и прижимается к концу.
Шире ряда кластер не становится: если не помещается и он один, он
прокручивается вбок без видимой полосы. На такой ширине включайте compact —
«текущая / всего» вместо номеров — или уменьшайте siblingCount. Ориентиры для
siblingCount: 1 (до семи позиций номеров) — ширина кластера с номерами:
size | кластер |
|---|---|
xs | ≈ 365px |
sm | ≈ 440px |
md | ≈ 525px |
lg | ≈ 595px |
С compact кластер при md занимает около 275px.
Сам компонент ширину не меряет: число позиций, зависящее от замера, разошлось бы между сервером и клиентом. Брейкпоинт выбирает раскладка страницы.
Доступность
Корень — role="navigation" с именем из локали (gr.pagination.label). Если
пагинаций на странице две (сверху и снизу таблицы), задайте ariaLabel — иначе
в обзоре диктора будут два одинаковых лендмарка.
Номера лежат в списке (<ul role="list">), поэтому диктор сообщает их
количество; многоточия из него исключены (aria-hidden). Текущая страница
помечена aria-current="page".
Смену страницы объявляет живая область: в компактном режиме её несёт видимый
индикатор, в обычном — скрытая строка «Страница N из M» (gr.pagination.status).
Размеры
size (xs…lg) читается из GrConfigProvider
(componentDefaults.GrPagination.size). Коробка номера — та же высота, что у
GrButton того же имени (28/32/40/44): номера и навигационные кнопки стоят в
одном ряду, и разойдись шкалы — ряд поедет. Поэтому же sm и md — разные
размеры, а не один и тот же рост с разным кеглем.
Пропы этого примера