useTable 分页表格
封装分页列表通用逻辑:分页状态、数据加载、搜索重置。基于 @pinia/colada 的 useQuery 实现服务端缓存。
返回的 list / total / page / pageSize / isLoading 可直接绑定到任意表格组件,下面以 @fx/pro 的 FxProTable 为例。
参数
ts
useTable<T>(options: {
key: () => (string | number)[]
query: (params: { page: number; page_size: number }) => Promise<{ data: { items: T[]; total: number } }>
defaultPageSize?: number // 默认 20
})返回值
| 属性 | 类型 | 说明 |
|---|---|---|
page | Ref<number> | 当前页码 |
pageSize | Ref<number> | 每页条数 |
total | ComputedRef<number> | 总条数 |
list | ComputedRef<T[]> | 当前列表数据 |
isLoading | Ref<boolean> | 加载状态 |
refetch | () => void | 重新加载当前页 |
search | () => void | 重置到第一页并重新加载 |
基础用法
page / pageSize 作为 useQuery 的 key,变化时自动重新加载。用 FxPagination 的 v-model 绑定它们即可实现分页切换,无需手动调用 refetch;list / isLoading 直接传给 FxProTable。
vue
<script setup>
import { useTable } from '@fx/hooks'
import { FxProTable } from '@fx/pro'
const { list, total, page, pageSize, isLoading } = useTable({
key: () => ['users'],
query: async ({ page, page_size }) => {
// 实际项目替换为接口请求:return adminApi.users.getList({ page, page_size })
const items = Array.from({ length: page_size }, (_, i) => ({
id: (page - 1) * page_size + i + 1,
name: `用户 ${(page - 1) * page_size + i + 1}`,
}))
return { data: { items, total: 23 } }
},
defaultPageSize: 5,
})
const columns = [
{ prop: 'id', label: 'ID', width: 80 },
{ prop: 'name', label: '姓名' },
]
</script>
<template>
<FxProTable :columns="columns" :data="list" :loading="isLoading" />
<FxPagination
v-model:current-page="page"
v-model:page-size="pageSize"
:total="total"
:page-sizes="[5, 10, 20, 50]"
layout="total, sizes, prev, pager, next, jumper"
/>
</template>搜索重置
search() 重置到第一页并重新加载,常配合搜索按钮使用。把搜索关键字加入 key,关键字变化也会自动重新加载。
vue
<script setup>
import { ref } from 'vue'
import { useTable } from '@fx/hooks'
import { FxProTable } from '@fx/pro'
import { FxBtn } from '@fx/components'
const keyword = ref('')
const {
list,
total,
page,
pageSize,
isLoading,
search,
} = useTable({
// keyword 作为 key 的一部分,变化即重新加载
key: () => ['users', keyword.value],
query: async ({ page, page_size }) => {
const items = Array.from({ length: page_size }, (_, i) => ({
id: (page - 1) * page_size + i + 1,
name: `${keyword.value || '用户'} ${(page - 1) * page_size + i + 1}`,
}))
return { data: { items, total: 23 } }
},
defaultPageSize: 5,
})
const columns = [
{ prop: 'id', label: 'ID', width: 80 },
{ prop: 'name', label: '姓名' },
]
</script>
<template>
<FxInput v-model="keyword" placeholder="输入关键字搜索" />
<FxBtn type="primary" @click="search">搜索</FxBtn>
<FxProTable :columns="columns" :data="list" :loading="isLoading" />
<FxPagination
v-model:current-page="page"
v-model:page-size="pageSize"
:total="total"
layout="total, prev, pager, next"
/>
</template>query 返回结构
query 需返回 { data: { items, total } },兼容常见 { code, message, data: { items, total } } 响应格式。
