# useTablePagination

## 使用方法

把当前页和翻页回调交给 `useTablePagination`，再把返回的插件放进 `Table` 的 `plugins`。

```ts
import { paginateData, useTablePagination } from '@astryx-vue/core/Table'
```

这个 hook 只画控件，行还是你自己切：`paginateData(rows, page, pageSize)` 返回当前页的窗口，同一个 `pageSize` 要同时给切片和配置。

页数靠 `totalItems` 算。已经知道页数时改给 `totalPages`；游标分页不知道总数时，只要后面还有内容就把 `hasMore` 设成 `true`。只有一页、也没有下一页时控件自己藏起来。

```ts
const page = ref(1)
const pageSize = 5
const plugin = useTablePagination(() => ({
  page: page.value,
  onPageChange(next) {
    page.value = next
  },
  totalItems: users.length,
  pageSize,
}))
const rows = computed(() => paginateData(users, page.value, pageSize))
```

`variant` 决定上一页和下一页之间放什么：页码、条数、紧凑的「第几页 / 共几页」、圆点，或者什么都不放。`position` 决定控件在表格上方、下方、上下都有，还是不要；取 `both` 时两块导航区的名字会区分开，读屏不会把它们当成同一个。

每次读配置都会重新取值，所以页码存在 `ref` 里时要传 getter。直接传对象也能跑，但控件会用第一次读到的页码。

## 示例

### Table — 分页数据

分页展示较大数据集的表格，一页一页翻。

```vue
<script setup lang="ts">
import type { TableColumn } from '@astryx-vue/core/Table'
import { paginateData, proportional, Table, useTablePagination } from '@astryx-vue/core/Table'
import { computed, ref } from 'vue'

interface User extends Record<string, unknown> {
  id: string
  name: string
  email: string
  role: string
}

const names = [
  'Alice Johnson',
  'Bob Smith',
  'Charlie Brown',
  'Diana Prince',
  'Eve Davis',
  'Frank Miller',
  'Grace Lee',
  'Hank Wilson',
  'Ivy Chen',
  'Jack Turner',
  'Karen White',
  'Leo Garcia',
  'Mia Thompson',
  'Noah Martinez',
  'Olivia Clark',
  'Paul Harris',
  'Quinn Walker',
  'Rachel Adams',
  'Sam Robinson',
  'Tina Scott',
]
const roles = ['Engineer', 'Designer', 'Manager', 'Admin', 'Analyst']
const users: User[] = names.map((name, index) => ({
  id: String(index + 1),
  name,
  email: `${name.split(' ')[0]!.toLowerCase()}@example.com`,
  role: roles[index % roles.length]!,
}))

const columns: TableColumn<User>[] = [
  { key: 'name', header: 'Name', width: proportional(1) },
  { key: 'email', header: 'Email', width: proportional(2) },
  { key: 'role', header: 'Role', width: proportional(1) },
]

const page = ref(1)
const pageSize = 5
const plugin = useTablePagination<User>(() => ({
  page: page.value,
  onPageChange(next) {
    page.value = next
  },
  totalItems: users.length,
  pageSize,
}))
const rows = computed(() => paginateData(users, page.value, pageSize))
</script>

<template>
  <Table
    :data="rows"
    :columns="columns"
    id-key="id"
    :plugins="{ pagination: plugin }"
  />
</template>
```

## 参数

`useTablePagination()` 只接一个配置对象。页码存在 `ref` 里时用 getter 包一层，控件每次读都能拿到最新的值：`useTablePagination(() => ({ ... }))`。

| 名称 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `page` | `number` | — | 必填。当前页，从 1 计。 |
| `onPageChange` | `(page: number) => void` | — | 必填。翻页时调用。 |
| `totalItems` | `number` | — | 全部条目数，用来算页数。没给它也没给 `totalPages` 时，控件只认 `hasMore`。 |
| `totalPages` | `number` | — | 总页数。只知道页数、不知道条目数时用它。它优先于从 `totalItems` 算出来的页数。 |
| `hasMore` | `boolean` | — | 后面还有没有下一页。游标分页用它：总数未知也能翻。为真时下一页按钮一直可点。 |
| `pageSize` | `number` | `10` | 每页条目数。切行的时候要用同一个数。 |
| `onPageSizeChange` | `(pageSize: number) => void` | — | 用户改每页条数时调用。它和 `pageSizeOptions` 都给，才会出现每页条数选择器。 |
| `pageSizeOptions` | `number[]` | `[10, 20, 50, 100]` | 可选的每页条数。要出现选择器还需要 `onPageSizeChange`。 |
| `variant` | `'pages' \| 'count' \| 'compact' \| 'dots' \| 'none'` | `'pages'` | 上一页和下一页之间放什么：页码按钮、「第几条到第几条 / 共几条」、紧凑的「第几页 / 共几页」、圆点，或者什么都不放。 |
| `position` | `'below' \| 'above' \| 'both' \| 'none'` | `'below'` | 控件放在表格的哪一侧。取 `'both'` 时上下各有一组。 |
| `align` | `'start' \| 'center' \| 'end'` | `'center'` | 控件的水平对齐。 |
| `size` | `'sm' \| 'md'` | `'md'` | 控件高度。 |
| `label` | `string` | 当前语言的「表格分页」 | 分页导航区的无障碍名称。取 `position: 'both'` 时两块导航区的名字会区分开，后面分别加 `(top)` 和 `(bottom)`，同类型地标不会重名。 |

## 返回值

`useTablePagination()` 返回一个 `TablePlugin&lt;T&gt;`，放进 `Table` 的 `plugins` 里。它填的是插件约定里的两个字段：

| 名称 | 类型 | 说明 |
| --- | --- | --- |
| `above` | `() => VNodeChild` | `position` 是 `'above'` 或 `'both'` 时，在表格上方画控件。 |
| `below` | `() => VNodeChild` | `position` 是 `'below'` 或 `'both'` 时，在表格下方画控件。 |

<code>position</code> 是 <code>'none'</code>，或者表格只有一页而且 <code>hasMore</code> 不是 <code>true</code> 时，两个都返回 <code>null</code>。
