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

相关推荐
小桥风满袖31 分钟前
极简三分钟ES6 - ES8中字符串扩展
前端·javascript
张拭心31 分钟前
这就是流量的力量吗?用豆包 AI 编程做的xhs小组件帖子爆了
前端·ai编程·豆包marscode
少年阿闯~~35 分钟前
CSS3的新特性
前端·javascript·css3
IT_陈寒41 分钟前
React性能优化:这5个Hook技巧让我的组件渲染效率提升50%(附代码对比)
前端·人工智能·后端
智能化咨询1 小时前
【Linux】【实战向】Linux 进程替换避坑指南:从理解 bash 阻塞等待,到亲手实现能执行 ls/cd 的 Shell
前端·chrome
Anson Jiang1 小时前
浏览器标签页管理:使用chrome.tabs API实现新建、切换、抓取内容——Chrome插件开发从入门到精通系列教程06
开发语言·前端·javascript·chrome·ecmascript·chrome devtools·chrome插件
掘金安东尼1 小时前
黑客劫持:周下载量超20+亿的NPM包被攻击
前端·javascript·面试
剑亦未配妥2 小时前
移动端触摸事件与鼠标事件的触发机制详解
前端·javascript
人工智能训练师8 小时前
Ubuntu22.04如何安装新版本的Node.js和npm
linux·运维·前端·人工智能·ubuntu·npm·node.js