useElTableExtendedInstance.ts
TypeScript
import type { ElTableExtendedInstance } from "@/interface";
import { ref, type Ref } from "vue";
/**
* ElTable 扩展实例 hook
* 该 hook 的作用是处理 ElTable 的列属性和列标签之间的映射关系
* @param tableRef 表格实例的引用,用于访问和操作表格的属性和方法
* @returns 返回一个对象,包含列属性和列标签的键值对以及获取这些键值对的方法
*/
export const useElTableExtendedInstance = (tableRef: Ref<ElTableExtendedInstance | null>) => {
// 列属性和列标签的映射表
const columnPropertyLabelMap = ref<Record<string, string>>({});
/**
* 将列信息提取为 Record 结构
* 该函数接收一个列数组,每个列包含 property 和 label 属性,并将其转换为一个键值对对象
* @param columns 列数组,包含每个列的 property 和 label 属性
* @returns 返回一个 Record 对象,其中键是列属性,值是列标签
*/
const extractColumnsToRecord = (columns: Array<{ property: string; label: string }>): Record<string, string> => {
return columns.reduce((acc, column) => {
acc[column.property] = column.label ?? "";
return acc;
}, {} as Record<string, string>);
};
/**
* 更新列属性和列标签的键值对
* 该函数通过访问表格实例的列信息,过滤出具有 property 属性的列,并调用 extractColumnsToRecord 函数
* 将其转换为键值对对象,然后将其赋值给 columnPropertyToLabelMap
*/
const updateColumnPropertyLabelMap = () => {
const tableInstance = tableRef.value;
if (!tableInstance || !tableInstance.store) return;
const columns = tableInstance.store?.states?.columns?.value;
if (!Array.isArray(columns)) return;
const filteredColumns = columns.filter(
(column) => column.property && typeof column.property === "string" && column.property.trim() !== ""
);
columnPropertyLabelMap.value = extractColumnsToRecord(filteredColumns);
};
// 返回列属性和列标签的键值对以及获取键值对的方法
return {
columnPropertyLabelMap,
updateColumnPropertyLabelMap
};
};
优化
TypeScript
import type { ElTableExtendedInstance } from "@/interface";
import { exportExcelFile } from "@/utils/excelUtils";
import { ref, type Ref } from "vue";
/**
* ElTable 扩展实例 hook
* 该 hook 的作用是处理 ElTable 的列属性和列标签之间的映射关系
* @param tableRef 表格实例的引用,用于访问和操作表格的属性和方法
* @returns 返回一个对象,包含列属性和列标签的键值对以及获取这些键值对的方法
*/
export const useElTableExtendedInstance = (tableRef: Ref<ElTableExtendedInstance | null>) => {
// 列属性和列标签的映射表
const columnPropertyLabelMap = ref<Record<string, string>>({});
/**
* 获取当前表格的有效列数组
* 如果表格实例或其状态无效,则返回 null
*/
const getTableColumns = (): Array<{ property: string; label: string }> | null => {
const instance = tableRef.value;
if (!instance || !instance.store || !instance.store.states || !instance.store.states.columns) {
return null;
}
const columns = instance.store.states.columns.value;
return Array.isArray(columns) ? columns : null;
};
/**
* 安全地从对象中获取指定属性的值
* 避免访问 null 或非对象类型时出错
*/
const getPropertySafely = <T extends Record<string, any>, K extends keyof T>(obj: T, key: K): T[K] | undefined => {
if (obj === null || typeof obj !== "object" || Array.isArray(obj)) {
return undefined;
}
return obj[key];
};
/**
* 解析单个列对象,转换为 property 和 label
* @param column 待解析的列对象
* @returns 若合法则返回 { property, label },否则返回 null
*/
const parseColumnToPropertyLabel = (column: any): { property: string; label: string } | null => {
if (typeof column !== "object" || column === null) {
return null;
}
const property = getPropertySafely(column, "property");
const label = getPropertySafely(column, "label");
if (typeof property !== "string" || property.trim() === "") {
return null;
}
const normalizedLabel = label == null ? "" : String(label).trim();
return {
property: property.trim(),
label: normalizedLabel
};
};
/**
* 将列信息提取为 Record 结构
* 该函数接收一个列数组,每个列包含 property 和 label 属性,并将其转换为一个键值对对象
* 注意:遇到重复 property 时,仅保留第一个出现的项
* @param columns 列数组,包含每个列的 property 和 label 属性
* @returns 返回一个 Record 对象,其中键是列属性,值是列标签
*/
const extractColumnsToRecord = (columns: Array<{ property: string; label: string }>): Record<string, string> => {
if (!Array.isArray(columns) || columns.length === 0) {
return {};
}
const resultMap: Record<string, string> = {};
for (const column of columns) {
const parsed = parseColumnToPropertyLabel(column);
if (!parsed) continue;
const { property, label } = parsed;
// 若有重复的 property,保留第一个出现的项
if (!(property in resultMap)) {
resultMap[property] = label;
}
}
return resultMap;
};
/**
* 更新列属性和列标签的键值对
* 该函数通过访问表格实例的列信息,过滤出具有 property 属性的列,并调用 extractColumnsToRecord 函数
* 将其转换为键值对对象,然后将其赋值给 columnPropertyToLabelMap
*/
const updateColumnPropertyLabelMap = () => {
const columns = getTableColumns();
if (!columns) {
columnPropertyLabelMap.value = {};
return;
}
columnPropertyLabelMap.value = extractColumnsToRecord(columns);
};
/**
* 表格数据导出为 Excel 文件
* @param filename 文件名
*/
const tableDataExportToExcelFile = (filename?: string) => {
const tableData = tableRef.value?.data ?? [];
if (Object.keys(columnPropertyLabelMap.value).length === 0) {
updateColumnPropertyLabelMap();
}
exportExcelFile(tableData, columnPropertyLabelMap.value, filename);
};
return {
tableDataExportToExcelFile
};
};
在组件中使用
ReagentTransactionsDrawer.vue
TypeScript
<script setup lang="ts" name="ReagentTransactionsDrawer">
import { useElTableExtendedInstance } from "@/hooks/useElTableExtendedInstance";
import type { ElTableExtendedInstance } from "@/interface";
// 表格实例对象
const tableRef = ref<ElTableExtendedInstance | null>(null);
const { tableDataExportToExcelFile } = useElTableExtendedInstance(tableRef);
// 导出
const onExportClick = () => {
// 表格数据导出为 Excel 文件
tableDataExportToExcelFile("流转记录");
};
</script>