el-table递归表头的坑

错误写法

在编写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是该写法的便捷版。

相关推荐
我不吃饼干4 小时前
在 React 中实现倒计时功能会有什么坑
前端·react.js
小小小小宇4 小时前
前端PerformanceObserver
前端
王者鳜錸4 小时前
PYTHON从入门到实践-18Django从零开始构建Web应用
前端·python·sqlite
拾光拾趣录4 小时前
ES6到HTTPS全链路连环拷问,99%人第3题就翻车?
前端·面试
haaaaaaarry5 小时前
Element Plus常见基础组件(二)
开发语言·前端·javascript
xyphf_和派孔明6 小时前
关于echarts的性能优化考虑
前端·性能优化·echarts
PyHaVolask6 小时前
HTML 表单进阶:用户体验优化与实战应用
前端·javascript·html·用户体验
A了LONE6 小时前
cv弹窗,退款确认弹窗
java·服务器·前端
AntBlack6 小时前
闲谈 :AI 生成视频哪家强 ,掘友们有没有推荐的工具?
前端·后端·aigc
花菜会噎住7 小时前
Vue3核心语法进阶(computed与监听)
前端·javascript·vue.js