Vue3封装表格useTable hooks,复用性更好

2,872 阅读2分钟

前言

CR公司其他大佬负责的项目-后台管理系统,主要就是很多列表页的展示,项目基于vite+vue+antdVue+ts, 开发新页面,cv大法就不用说了,每次直接cv老页面,然后改改改改改改改改改改改改改改改改改改改改改改改改改改, 代码都是一摸一样,就很烦。。。。

目的

这里就通过自定义hook优化List业务代码,使cv更简单,减少代码量,提高代码复用性、阅读性,提高工作效率。

hook options

fielddesciption
columns列表配置
firstDontLoad是否初次加载数据
extraParams额外参数
mapRequest参数处理函数
mapResponse请求处理函数
ajax请求
throwErrorMessageWhenResNotFitDefined是否抛出异常
paginationConfig分页配置
export type TableResponse<T extends Record<string, any>> = {
  total: number;
  list: T[];
};

export type TableRequest<T extends Record<string, any>> = {
  isAsc?: string; //"desc" | "asc";
  oderByColumn?: string;
  currentPage: number;
  pageSize: number;
} & T;

type Option<
  ExtraParams extends Record<string, any>,
  RecordRaw extends Record<string, any>
> = {
  columns?: ColumnsType<RecordRaw>;
  firstDontLoad?: boolean;
  extraParams?: ExtraParams;
  mapRequest?: (params: any) => any;
  mapResponse?: (dataSource: RecordRaw[], other: any) => RecordRaw[];
  ajax: (
    params: TableRequest<ExtraParams>
  ) => Promise<TableResponse<RecordRaw>>;
  throwErrorMessageWhenResNotFitDefined?: boolean;
  paginationConfig?: Partial<TablePaginationConfig>;
};

useTable Hook

export function useTable<ExtraParams, RecordRaw>(
  option: Option<ExtraParams, RecordRaw>
) {
  const pagination = reactive<TablePaginationConfig>({
    total: 0,
    current: 1,
    pageSize: 10,
    pageSizeOptions: ["10", "20", "50", "100"],
    showQuickJumper: true,
    showSizeChanger: true,
    showTotal: function (total) {
      return "共" + total + "条";
    },
    ...(option.paginationConfig ?? {}),
  });

  const sorter = ref<SorterResult<any> | null>(null);

  const loading = ref(!option.firstDontLoad);

  const dataSource = ref<RecordRaw[]>([]);

  const scroll = ref({
    x:
      option.columns?.reduce(
        (prev, cur) => prev + (typeof cur.width === "number" ? cur.width : 120),
        0
      ) ?? 1300,
  });

  const fetchData = async () => {
    loading.value = true;
    try {
      const params = (
        option?.extraParams ? toRaw(unref(option.extraParams)) : {}
      ) as ExtraParams;

      const t = {
        ...params,
        isAsc: sorter.value?.order?.slice(0, -3) ?? undefined,
        oderByColumn: sorter.value?.field as string,
        currentPage: pagination.current!,
        pageSize: pagination.pageSize!,
      };

      const p =
        typeof option?.mapRequest === "function" ? option.mapRequest(t) : t;

      const { total, list, ...other } = await option.ajax(p);
      if (Array.isArray(list)) {
        if (typeof option.mapResponse === "function") {
          dataSource.value = option.mapResponse(list, other) as any;
        } else {
          dataSource.value = list as any;
        }
        pagination.total = total;
      } else if (option.throwErrorMessageWhenResNotFitDefined) {
        message.error("接口格式错误,请联系管理员!");
      }
    } catch (e) {
      console.error(e);
    } finally {
      loading.value = false;
    }
  };

  onMounted(() => {
    if (option.firstDontLoad) {
      return;
    }
    fetchData().then();
  });

  const onChange: TableProps["onChange"] = (p, _, s) => {
    Object.keys(p).forEach((key) => {
      (pagination as any)[key] = (p as any)[key];
    });
    sorter.value = s as SorterResult<RecordRaw>;
    fetchData().then();
  };

  const onRefresh = (reset: boolean = false) => {
    if (reset) {
      pagination.current = 1;
      sorter.value = null;
    }
    fetchData().then();
  };

  return {
    columns: option?.columns ?? [],
    onChange,
    pagination,
    loading,
    dataSource,
    onRefresh,
    scroll,
  };
}

使用方法

<template>
    <Table :scroll="{ x: 1300 }"
            :loading="loading"
            :columns="columns"
            @change="onChange"
            :data-source="dataSource"
            :pagination="pagination"
    >
    </Table>
</template>
<script setup lang="ts">
const { loading, pagination, onChange, onRefresh, dataSource } = useTable({
  extraParams,
  firstDontLoad: true,
  ajax: api,
  mapResponse: (data) =>
    data.map((c, i) => ({
      ...c,
      index: i + 1,
    })) ?? [],
});
</script>