useTable 表格数据管理钩子函数文档
一、功能概述
useTable 是基于 Vue 3 的响应式表格数据管理钩子,用于统一处理表格数据的加载、分页、搜索和格式化。它封装了常见的表格操作逻辑,支持与后端接口集成,适用于中后台管理系统的表格场景。
二、核心特性
响应式状态管理
- 包含加载状态
loading、表格数据data、分页信息pagination等响应式数据 - 状态变化时自动触发视图更新
- 包含加载状态
灵活的分页支持
- 可通过
hasPagination开关控制是否启用分页 - 支持自定义分页初始值(通过
pagination函数传入)
- 可通过
多功能数据处理
- 自动合并查询参数与分页参数
- 支持数据格式化(
formatter函数) - 提供搜索(
onSearch)、刷新(onRefresh)等常用操作
可配置化接口
- 支持动态传入 API 接口、查询参数、初始化加载等配置
三、接口定义
1. 分页参数接口(Pagination)
typescript
interface Pagination {
pageNo: number; // 当前页码(从 1 开始)
pageSize: number; // 每页条数
total: number; // 总数据量
}2. 表格状态接口(TableState)
typescript
interface TableState {
pagination: Pagination; // 分页状态
loading: boolean; // 加载状态
data: any[]; // 表格数据
}3. 钩子函数参数(UseTableProps)
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
api | (params: any) => Promise<any> | 是 | - | 数据请求接口(需返回 Promise) |
query | () => any | 否 | {} | 查询参数生成函数(返回对象,可异步) |
formatter | (data: any[]) => any[] | 否 | - | 数据格式化函数(用于处理接口返回的原始数据) |
hasPagination | boolean | 否 | true | 是否启用分页 |
init | boolean | 否 | true | 是否在初始化时自动加载数据 |
pagination | () => Pagination | 否 | () => ({ pageNo: 1, pageSize: 10, total: 1 }) | 分页初始值生成函数 |
四、返回值说明
| 名称 | 类型 | 说明 |
|---|---|---|
pagination | Ref<Pagination> | 分页状态响应式对象 |
loading | Ref<boolean> | 加载状态响应式变量 |
data | Ref<any[]> | 表格数据响应式数组 |
onSearch | () => Promise<void> | 搜索函数(重置页码为 1 并重新加载数据) |
onRefresh | () => Promise<void> | 刷新函数(保留当前页码并重新加载数据) |
loadData | () => Promise<void> | 数据加载函数(可手动调用) |
hasPagination | boolean | 是否启用分页的标识值 |
五、使用示例
场景 1:基础表格(带分页)
vue
<template>
<div>
<el-table :data="data" v-loading="loading">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="age" label="年龄" />
</el-table>
<el-pagination
v-if="hasPagination"
:total="pagination.total"
:current-page="pagination.pageNo"
:page-size="pagination.pageSize"
@current-change="(pageNo) => { pagination.pageNo = pageNo; loadData(); }"
@size-change="(pageSize) => { pagination.pageSize = pageSize; loadData(); }"
/>
</div>
</template>
<script setup>
import { useTable } from '@eco-library/hooks';
import { getUsers } from '@/api/user'; // 假设存在该接口
const { data, loading, pagination, loadData } = useTable({
api: getUsers, // 接口函数(需返回 { data: { list, total } } 格式)
query: () => ({ status: 'active' }), // 固定查询参数
formatter: (list) => list.map(item => ({ ...item, age: item.age + 1 })), // 数据格式化
});
// 手动触发搜索
const handleSearch = () => {
onSearch();
};
</script>场景 2:无分页表格(字典数据)
vue
<template>
<el-table :data="data" v-loading="loading" />
</template>
<script setup>
import { useTable } from '@eco-library/hooks';
import { getDictData } from '@/api/dict'; // 返回平铺数组
const { data, loading } = useTable({
api: getDictData,
hasPagination: false, // 关闭分页
formatter: (data) => data.map(item => ({ label: item.name, value: item.id })),
});
</script>场景 3:动态查询参数(带搜索框)
vue
<template>
<el-input v-model="searchKey" placeholder="搜索姓名" @change="handleSearch" />
<TableComponent />
</template>
<script setup>
import { ref } from 'vue';
import { useTable } from '@eco-library/hooks';
import { searchUsers } from '@/api/user'; // 支持 keyword 参数
const searchKey = ref('');
const { onSearch } = useTable({
api: searchUsers,
query: async () => ({ keyword: searchKey.value }), // 动态查询参数(支持异步)
});
const handleSearch = () => {
onSearch(); // 触发搜索并重置页码
};
</script>六、注意事项
接口返回格式要求
- 启用分页时,接口需返回
{ data: { list: any[], total: number } }格式 - 关闭分页时,接口需返回
{ data: any[] }或直接返回数组
- 启用分页时,接口需返回
性能优化
- 大数据量场景建议开启虚拟滚动(如使用
vue-virtual-scroller) - 可通过
nextTick确保 DOM 更新后再执行数据加载(如动态获取查询参数)
- 大数据量场景建议开启虚拟滚动(如使用
类型安全
建议为api接口和formatter函数添加类型声明,避免运行时错误:typescriptinterface User { name: string; age: number; } const formatter: (data: User[]) => User[] = (list) => list;
七、扩展建议
1. 支持动态列配置
typescript
// 扩展钩子,添加列配置管理
export function useTableWithColumns<T>(props: UseTableProps<T>) {
const { data, ...rest } = useTable(props);
const columns = ref<TableColumn<T>[]>([
{ prop: 'name', label: '姓名' },
{ prop: 'age', label: '年龄' }
]);
return { ...rest, columns };
}2. 添加加载更多功能
typescript
// 扩展钩子,支持滚动加载更多
export function useTableInfiniteScroll(props: UseTableProps) {
const { loadData, pagination, hasPagination } = useTable(props);
const loadMore = async () => {
if (!hasPagination || pagination.value.pageNo * pagination.value.pageSize >= pagination.value.total) return;
pagination.value.pageNo++;
await loadData();
};
return { ...rest, loadMore };
}八、依赖说明
- 核心依赖:Vue 3.x(
reactive、toRefs、nextTick) - 工具函数:
xCloneDeep(深度克隆工具,需确保其兼容性) - UI 组件:示例中使用 Element Plus,实际使用时需替换为项目组件库
