vue3封装一个快速查询表格数据的hook,高亮搜索关键字,减少重复代码,提高产出速度

因为项目中需要很多查询页面,重复写查询逻辑费时费力,每个查询页面的基本逻辑都是:定义查询参数=>调用接口发送参数=>拿到参数赋值给表格或其他组件回显=>配置分页组件实现分页这么一个过程,所以就封装了一个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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独断万古的伊莉雅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值