因为项目中需要很多查询页面,重复写查询逻辑费时费力,每个查询页面的基本逻辑都是:定义查询参数=>调用接口发送参数=>拿到参数赋值给表格或其他组件回显=>配置分页组件实现分页
这么一个过程,所以就封装了一个hook
只需要传进来查询参数(无需传分页参数),接口就可以完成上方所有逻辑,还能高亮搜索匹配关键字,如果hook的处理数据逻辑不适用接口返回参数,还可以传递一个自定义处理参数的函数
我使用的antdVue组件,你可以换成自己实际使用的组件库,记得修改这部分
泛型T继承的Recordable为全局类型定义:
declare type Recordable<T = any, K = string> = Record<K extends null | undefined ? string : K, T>;
hook定义
import type { TablePaginationConfig, TableProps } from 'ant-design-vue';
/** 使用此hook快速获取表格数据及实现分页等功能逻辑
*
* @param {Object} params 查询参数
* @param {Function} queryApi 要调用的接口
* @param {Function} handleRes 自定义接口结果处理,如果接口返回字段和默认取的字段不一致,可传此参数
* @param {String} matchFields 匹配字段名,搜索时匹配结果关键字进行高亮
*/
export function useTableQuery<T extends Recordable>(
params: Recordable,
queryApi: Fn,
handleRes?: Fn,
matchFields?: string | { queryField: string; resField: string },
) {
// 接口返回的参数会赋值到这里,供外部使用
const queryData = ref<T[]>([]);
// 加载中变量
const tableLoading = ref(false);
//基本分页参数
const baseQueryParams = ref({
pageSize: 10,
pageNum: 1,
total: 0,
});
//基本分页组件配置
const paginationConfig = computed(() => {
return {
current: baseQueryParams.value.pageNum,
defaultPageSize: baseQueryParams.value.pageSize,
total: baseQueryParams.value.total,
};
});
//核心:查询数据方法;isSearch是点击搜索时需要传递的参数,要重置分页参数
function getTableData(isSearch?: boolean) {
Object.keys(params).forEach((key) => (params[key] = unref(params[key])));
tableLoading.value = true;
isSearch && (baseQueryParams.value.pageNum = 1);
queryApi({ ...unref(params), ...baseQueryParams.value })
.then((res: Response) => {
if (handleRes) {
handleRes(res);
} else {
queryData.value = res.rows;
if (matchFields) {
queryData.value.forEach((item: Recordable) => {
if (typeof matchFields === 'string') {
if (!unref(params)[matchFields]) return;
item[matchFields] = matchText(unref(params)[matchFields], item[matchFields]);
} else {
if (!unref(params)[matchFields.queryField]) return;
item[matchFields.resField] = matchText(
unref(params)[matchFields.queryField],
item[matchFields.resField],
);
}
});
}
baseQueryParams.value.total = res.total;
}
tableLoading.value = false;
})
.catch((err: Response) => {
tableLoading.value = false;
});
}
/**
* 重置表单方法
* @param {Object} formRef 传入表单对象,调用重置字段方法
* @param {Function} queryFn 自定义查询方法
*/
function resetParams(formRef: any, queryFn?: Fn) {
formRef.resetFields();
baseQueryParams.value.pageNum = 1;
baseQueryParams.value.pageSize = 10;
baseQueryParams.value.total = 0;
queryFn ? queryFn() : getTableData();
}
//切换分页或每页条数方法(这个适配antdVue,如果不适配你的组件库,请修改)
const paginationChange: TableProps['onChange'] = (e: TablePaginationConfig | number) => {
console.log(e);
if (typeof e === 'number') {
baseQueryParams.value.pageNum = e;
} else {
baseQueryParams.value.pageNum = e.current as number;
baseQueryParams.value.pageSize = e.pageSize as number;
}
getTableData();
};
return {
queryData,
tableLoading,
paginationConfig,
baseQueryParams,
getTableData,
resetParams,
paginationChange,
};
}
在script使用hook
import { useTableQuery } from '@/hooks/useTableQuery';
// 查询参数
const queryParams = ref({
id: '',
name:''
});
// 返回数据类型
interface IDetailsData{
info:string
}
// 取出所需变量和方法
const { queryData, tableLoading, paginationConfig, getTableData, paginationChange } =
useTableQuery<IDetailsData>(queryParams, queryApi,undefined,'name');
// 调用
onMounted(()=>{
queryParams.id = 123
getTableData()
})
自定义处理数据方法
// 如果hook里的处理方法不适配接口参数,还可以传递一个自定义处理函数
const {
queryData,
tableLoading,
paginationConfig,
baseQueryParams,
getTableData,
resetParams,
paginationChange,
} = useTableQuery<ILibraryData>(formState, queryApi, formatFun);
function formatFun(res: IResponse) {
if (res.code === 200) {
baseQueryParams.value.pageNum = res.result.pageNum;
baseQueryParams.value.total = res.result.total;
queryData.value = res.result.list;
}
}
在组件中使用
//这个是antd组件,如果组件库不一样,请修改为实际使用方法
<!-- 表单 -->
<a-form
layout="inline"
ref="formRef"
style="row-gap: 10px; padding: 20px"
:model="formState"
@finish="getTableData(true)"
>
<a-form-item label="名称">
<a-input
v-model:value="queryParams.name"
placeholder="请输入名称"
allow-clear
/>
</a-form-item>
<a-form-item>
<a-button type="primary" html-type="submit"> 查询 </a-button>
</a-form-item>
<a-form-item>
<a-button @click="resetParams(formRef)"> 重置 </a-button>
</a-form-item>
</a-form>
<!-- 表格 -->
<a-table
class="details-table"
:columns="columns"
:data-source="queryData" //hook返回的数据变量
:pagination="paginationConfig" //hook返回的分页配置
:loading="tableLoading" //hook返回的加载中
@change="paginationChange" //hook返回的修改分页方法
@showSizeChange="paginationChange" //hook返回的修改分页方法
>
<template #bodyCell="{ column, record }">
<!--使用高亮匹配字段-->
<template v-if="column.dataIndex === 'title'">
<div v-html="record[column.dataIndex]" />
</template>
</template>
</a-table>