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

相关推荐
To_OC7 小时前
写了三遍 Todo List,我终于搞懂了 React 父子组件到底怎么通信
前端·javascript·react.js
勇往直前plus8 小时前
Vue3(篇一) 核心概念——响应式模板语法与组件基础
前端·javascript·vue.js
咩咩啃树皮8 小时前
第43篇:Vue3计算属性(computed)完全精讲——缓存机制、依赖计算、业务最优解
前端·vue.js·缓存
徐小夕10 小时前
花了一周,3亿tokens,我开源了一款 Word 文档智能审查平台,文稿自动质检+可视化分析,告别低效人工审核
前端·算法·github
kyriewen11 小时前
别再乱用useEffect了——你写的10个里有8个不该存在
前端·javascript·react.js
Ivanqhz11 小时前
Rust &‘static str浅析
java·前端·javascript·rust
IT_陈寒12 小时前
SpringBoot这个分页坑,我踩了三天才爬出来
前端·人工智能·后端
颜酱12 小时前
05 | 召回前置准备:根据业务数据库生成各数据库(读取配置阶段)
前端·人工智能·后端
zandy101112 小时前
衡石 Agentic BI的ReAct 推理框架在 Agentic BI 中的工程化实践
前端·javascript·react.js
罗超驿12 小时前
JavaEE进阶之路:从Web架构原理到HTML标签全解析
前端·html·web·javaee