错误写法
在编写el-table遇到的坑特此记录
vue
<script setup lang="ts">
const tableProps = [
{
label: "来电",
props: "call",
children: null,
},
{
label: "姓名",
props: "name",
children: null,
},
{
label: "年龄",
props: "age",
children: null,
},
{
label: "邮箱",
props: "email",
children: null,
},
{
label: "家庭",
props: null,
children: [
{
label: "父亲",
props: "fater",
children: null,
},
{
label: "母亲",
props: "mother",
children: null,
},
],
},
];
</script>
<template>
<el-table
:cell-style="{
textAlign: 'center',
}"
:header-cell-style="{
textAlign: 'center',
background: '#f2f3f2',
color: '#000',
}"
:data="data"
>
<el-table-column type="index" label="序号" width="100" />
<TableColumn :tableProps="tableProps" />
</el-table>
</template>
vue
TableColumn.vue
<script setup lang="tsx">
defineOptions({
name: "TableColumn",
});
type PropsGroup =
| {
label: string;
props: string;
children: null;
}
| {
label: string;
props: null;
children: PropsGroup[];
};
interface PropsPaginantion {
tableProps: PropsGroup[];
}
const props = withDefaults(defineProps<PropsPaginantion>(), {
tableProps: () => [],
});
onMounted(() => {
console.log(props.tableProps);
});
</script>
<template>
<template
v-for="(item, index) in props.tableProps"
:key="item.props || index"
>
<el-table-column
v-if="typeof item.props === 'string'"
:label="item.label"
:prop="item.props"
/>
<el-table-column
:label="item.label"
v-else-if="'children' in item && Array.isArray(item.children)"
>
<TableColumn :table-props="item.children" />
</el-table-column>
</template>
</template>
<style scoped lang="scss"></style>
该写法总体逻辑是采用递归组件去判断children是否有值进行自我调用,但页面渲染并没有第二层
原因未知,但deubgger编译后的代码中发现第二层级执行过

解决思路
使用tsx编写组件
tsx
import { ElTable, ElTableColumn } from "element-plus";
type PropsGroup =
| {
label: string;
props: string;
children: null;
}
| {
label: string;
props: null;
children: PropsGroup[];
};
const TableHeaderCreate = defineComponent({
props: {
data: Array,
tableProps: {
type: Array<PropsGroup>,
require: true,
},
cellStyle: Object,
headerCellStyle: Object,
},
setup(props, ctx) {
const tablePropsConfig = props.tableProps || [];
const generateColumns = (tableProps: PropsGroup[]) => {
return tableProps.map((item) => {
if (item.children) {
return (
<ElTableColumn label={item.label}>
{generateColumns(item.children)}
</ElTableColumn>
);
} else {
return <ElTableColumn label={item.label} prop={item.props} />;
}
});
};
return () => (
<>
<ElTable
cellStyle={props.cellStyle}
headerCellStyle={props.headerCellStyle}
data={props.data}
>
{generateColumns(tablePropsConfig)}
</ElTable>
</>
);
},
});
export default TableHeaderCreate;
通过封装成单独组件在通过函数递归实现表头递归(tsx还是比template灵活)
方案二 template中使用h函数
vue
<script setup lang="tsx">
defineOptions({
name: "TableColumn",
});
type PropsGroup =
| {
label: string;
props: string;
children: null;
}
| {
label: string;
props: null;
children: PropsGroup[];
};
interface PropsPaginantion {
tableProps: PropsGroup[];
data: Array<any>;
}
const props = withDefaults(defineProps<PropsPaginantion>(), {
tableProps: () => [],
});
const generateColumns = (pro: { table: PropsGroup[] }) => {
return pro.table.map((item) => {
if (item.children) {
return h(
ElTableColumn,
{ label: item.label },
h(generateColumns, {
table: item.children,
})
);
} else {
return h(ElTableColumn, { label: item.label, prop: item.props });
}
});
};
</script>
<template>
<el-table>
<el-table-column type="index" label="序号" width="100" />
<component :is="generateColumns" :table="props.tableProps" />
</el-table>
</template>
<style scoped lang="scss"></style>
核心逻辑还是generateColumns函数递归只是使用了component搭配h函数实现,本质上tsx是该写法的便捷版。