在 Vue 中处理动态字段的表格(表头和内容均根据接口返回数据动态生成)
核心思路
- 动态解析表头:从接口返回的数据中提取所有的字段(基于首个对象或合并所有对象的键)。
- 动态渲染内容:通过
v-for
循环动态生成表格列,并用作用域插槽处理动态字段内容。
// 示例数据
const mockData = [
{ id: 1, name: "Alice", age: 25, email: "alice@example.com" },
{ id: 2, title: "Engineer", salary: 8000 }, // 缺少某些字段
{ product: "Phone", price: 599.99, stock: 100 } // 完全不同的字段
];
1. 动态提取表头
// 动态生成表头(去重后的所有字段)
const tableHeaders = computed(() => {
const headers = new Set();
mockData.forEach(item => {
Object.keys(item).forEach(key => headers.add(key));
});
return Array.from(headers);
});
2. 动态渲染表格
<template>
<el-table :data="tableData" border style="width: 100%">
<!-- 动态生成表头 -->
<el-table-column
v-for="header in tableHeaders"
:key="header"
:prop="header"
:label="header"
>
<!-- 作用域插槽处理动态内容 -->
<template #default="{ row }">
<span v-if="row[header] !== undefined">
{{ formatField(header, row[header]) }}
</span>
<span v-else class="empty-cell">-</span>
</template>
</el-table-column>
</el-table>
</template>
<script setup>
// 可选:字段格式化逻辑(如日期、金额)
const formatField = (key, value) => {
switch (key) {
case 'price':
return `$${value.toFixed(2)}`;
case 'createdAt':
return new Date(value).toLocaleDateString();
default:
return value;
}
};
</script>
3. 优化与扩展
表头友好名称映射为动态字段添加中文映射:
<script setup>
// 表头映射配置
const headerMap = {
id: "ID",
name: "姓名",
age: "年龄"
……
};
// 修改表头生成逻辑
const tableHeaders = computed(() => {
/* 同上 */
return Array.from(headers).map(key => ({
key,
label: headerMap[key] || key // 使用映射或默认字段名
}));
});
</script>
<!-- 调整模板中的 label -->
<el-table-column
v-for="header in tableHeaders"
:key="header.key"
:prop="header.key"
:label="header.label"
>
处理嵌套对象
如果接口返回嵌套对象(如 { info: { name: 'Alice' } }
),可通过递归展开:
// 递归提取所有字段(平铺嵌套对象)
const flattenObject = (obj, prefix = '') => {
return Object.keys(obj).reduce((acc, key) => {
const pre = prefix ? `${prefix}.` : '';
if (typeof obj[key] === 'object' && obj[key] !== null) {
Object.assign(acc, flattenObject(obj[key], pre + key));
} else {
acc[pre + key] = obj[key];
}
return acc;
}, {});
};
// 在数据预处理阶段平铺数据
const flattenedData = mockData.map(item => flattenObject(item));