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

相关推荐
njsgcs12 分钟前
opencascade.js stp vite webpack 调试笔记
开发语言·前端·javascript
T0uken1 小时前
【前端】:单 HTML 去除 Word 批注
前端·html·word
st紫月1 小时前
用vue和go实现登录加密
前端·vue.js·golang
岁岁岁平安1 小时前
Vue3学习(组合式API——计算属性computed详解)
前端·javascript·vue.js·学习·computed·计算属性
HWL56792 小时前
Express项目解决跨域问题
前端·后端·中间件·node.js·express
刺客-Andy2 小时前
React 第三十九节 React Router 中的 unstable_usePrompt Hook的详细用法及案例
前端·javascript·react.js
Go_going_2 小时前
【js基础笔记] - 包含es6 类的使用
前端·javascript·笔记
浩~~3 小时前
HTML5 浮动(Float)详解
前端·html·html5
AI大模型顾潇4 小时前
[特殊字符] 本地大模型编程实战(29):用大语言模型LLM查询图数据库NEO4J(2)
前端·数据库·人工智能·语言模型·自然语言处理·prompt·neo4j
工业互联网专业4 小时前
基于springboot+vue的医院门诊管理系统
java·vue.js·spring boot·毕业设计·源码·课程设计·医院门诊管理系统