Skip to content

useTable 分页表格

封装分页列表通用逻辑:分页状态、数据加载、搜索重置。基于 @pinia/coladauseQuery 实现服务端缓存。

返回的 list / total / page / pageSize / isLoading 可直接绑定到任意表格组件,下面以 @fx/proFxProTable 为例。

参数

ts
useTable<T>(options: {
  key: () => (string | number)[]
  query: (params: { page: number; page_size: number }) => Promise<{ data: { items: T[]; total: number } }>
  defaultPageSize?: number // 默认 20
})

返回值

属性类型说明
pageRef<number>当前页码
pageSizeRef<number>每页条数
totalComputedRef<number>总条数
listComputedRef<T[]>当前列表数据
isLoadingRef<boolean>加载状态
refetch() => void重新加载当前页
search() => void重置到第一页并重新加载

基础用法

page / pageSize 作为 useQuery 的 key,变化时自动重新加载。用 FxPaginationv-model 绑定它们即可实现分页切换,无需手动调用 refetchlist / 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 } } 响应格式。