最近在阅读 aHooks 文档时,我发现了一个非常实用的函数——useAntdTable,它封装了 Ant Design Table 组件常见的逻辑。刚好最近我自己也封装了一个类似的 Table 组件 x-table,于是我决定尝试封装一个类似的函数。
与 React 的 Hook 类似,Vue3 提供了组合式 API ,它可以帮助我们更方便地封装和复用有状态逻辑。下面我将介绍如何使用 Vue3 的组合式函数来实现一个简单高效的 useTable 函数。
使用
首先,让我们看一下 useTable 是如何使用的。
基础用法
<template>
<x-table :columns="columns" v-bind="tableProps" >
</template>
<script setup lang='ts'>
const { tableProps } = useTable(getArticleList)
</script>
简单吗?只要几行代码就能轻松搞定一个报表页面,剩下的时间我们是不是就可以用来愉快的学(摸)习(鱼)了。
高级用法
除了基本用法,useTable 函数还提供了其他配置项。
const options = {
immediate: true, // 默认立即加载数据
pageable: true, // 是否可分页,默认为true
pageNum: 1, // 默认的分页参数
pageSize: 10, // 默认的分页参数
onBeforeRequest (params) => {
console.log("请求前:", params);
return params
},
onSuccess: (data) => {
console.log("请求成功:", data);
},
onError: (error) => {
console.error("请求失败:", error);
},
onFinally: () => {
console.log("请求结束");
},
};
const { loading, form, data, total, tableProps, query, reset } = useTable(
service,
options
);
设计与实现
类型定义
export default function useTable<
TService extends UseTableService<any, any>,
TDataItem extends ExtractServiceDataItem<TService>,
TParams extends ExtractServiceParams<TService>,
>(
service: TService,
defaultParams?: TParams,
options?: UseTableOptions<TDataItem, ExtractServiceParams<TService>>,
): UseTableReturn<TDataItem, TParams>
useTable 函数接受两个参数:service 、defaultParams 和 options。service 是请求方法,而 defaultParams 和 options 是可选参数。
通过使用泛型参数,我们可以根据传入的 getArticleList 方法来推断出具体的参数和返回值类型。
配置项
interface UseTableOptions<TDataItem, TParams> {
immediate?: boolean
pageable?: boolean
pageSize?: number
pageNum?: number
onBeforeRequest?: (params: TParams, paging: PagingRequest) => TParams
onChange?: (data: XTableChangeData) => void
onSuccess?: (data: TableServiceResponse<TDataItem>) => void
onError?: (error: unknown) => void
onFinally?: () => void
}
immediate: 是否立即加载数据pageable: 是否需要分页pageSize: 分页数量pageNum: 当前页onBeforeRequest: 请求前的参数处理onSuccess: 请求成功时的回调onError: 请求失败时的回调onFinally: 请求结束时的回调
返回值
interface UseTableReturn<TDataItem, TParams> {
query: () => Promise<void>
reset: () => Promise<void>
abort: () => void
loading: Ref<boolean>
form: Ref<TParams>
data: Ref<TDataItem[]>
tableProps: ComputedRef<{
loading: boolean
dataSource: TDataItem[]
pageNum: number
pageSize: number
total: number
pageable: boolean
onChange: (data: XTableChangeData) => void
}>
}
函数返回一个包含以下属性的对象:
query获取数据的函数reset重置表格参数,并重新获取数据abort取消请求的函数loading: 接口请求状态form: 响应式表单数据data: 接口返回的表格数据tableProps:表格的属性,包括表格数据、分页排序等
tableProps 主要是配合 x-table 使用,提供表格需要的一些属性。
请求方法
const fetchData = async () => {
try {
abortController?.abort()
loading.value = true
abortController = new AbortController()
const res = await service(getParams(), {
signal: abortController.signal,
})
if (pageable) {
const ret = res.data as PagingResult<TDataItem[]>
data.value = ret.list
total.value = ret.count
} else {
const ret = res.data as TDataItem[]
data.value = ret
total.value = ret.length
}
onSuccess?.(res)
} catch (error) {
if (!(error instanceof DOMException && error.name === 'AbortError')) {
onError?.(error)
}
} finally {
loading.value = false
onFinally?.()
}
}
在 fetchData 函数中,我们根据配置项的设置来发起数据请求,并根据返回结果更新相应的数据。同时,在请求过程中,我们可以调用成功、失败和结束时的回调函数,以便处理额外的逻辑。
完整的代码和 Demo 可以在我的 GitHub 仓库 ares-admin 中查看。
总结
通过 useTable 函数,我们可以轻松实现一些常见的业务功能,提高代码的可维护性和复用性,节省开发时间。需要注意的是,由于本文中 useTable 没有在项目中实践,可能有一些不完善的地方,仅供参考学习。
最后,欢迎大家在评论区讨论学习,分享自己的经验和更好的想法。