table可视化合并、生成组件开发

74 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

table可视化合并、生成组件开发

平常看多了,xxx 低代码平台、xxx低代码平台,眼花缭乱。

今天我们也来实现一个"所见即所得"的需求:table可视化合并、生成组件。 image.png 项目地址

为什么要做这样的一个组件

最近的工作业务中心都在 erp 平台上,报表奇多;经常有需要导出报表模板给后端,让后端生成数据的情况,出于这个目的,我想做一个低代码的报表生成器,提供给产品和后端。

步骤一:生成table

我选择使用原生的 table + td 元素来进行;表格的数组我们选择使用二维数组来进行存放 image.png

核心代码

// 创建新表格数据
const createdTable = (row: number, column: number) => {
  clear();
  if (!row && !column) {
    tableData.value = [];
    return;
  }
  tableData.value = Array(row)
    .fill(0)
    .map((item, index) => {
      const res: TdOption[] = [];
      // 列的标志
      for (let columnIndex = 0; columnIndex < column; columnIndex++) {
        res.push(new TdOption(index, columnIndex));
      }
      return res;
    });
};

这里的TdOption是我们为每一个 td项目设置的一个类,它包含:

  • colSpan:表示该单元格占据多少列
  • rowSpan:表示该单元格占据多少行
  • show:表示该单元格是否显示
  • value:表示该单元格的内容
  • id
  • style 其中colSpan、rowSpan、show、id是我们之后进行单元格合并的重要数据

步骤二:可以合并

既然是表格,那么就要可以做到表格合并嘛!

合并目标

image.png

合并结果

image.png

核心代码:

// 合并单元格
const merge = () => {
  if (selectDomList.value.length < 2) {
    return;
  }
  // const start = selectDomList.value[0]; // 开始节点

  // let value = tableData.value[start.row][start.column];
  const { row, column } = selectDomList.value[0];
  let targetNode = {
    id: `${row}-${column}`,
    row,
    column,
  };
  let value: TdOption = new TdOption();
  selectDomMap.value.delete(targetNode.id); // 从合并的表格中删除掉我们用来合并的节点防止重复
  // 不仅要转换表格的合并值
  // 首先合并行
  // 从起始行开始 合并每一个单元行
  for (let i = 0; i < tableData.value.length; i++) {
    tableData.value[i] = tableData.value[i].filter((subItem, subIndex) => {
      const {
        id,
        style: { width, height },
        colSpan,
        rowSpan,
        row,
        column
      } = subItem;
      // 如果当前节点就是我们要进行合并的第一个节点
      // 就将这个节点取出来进行合并操作
      if (targetNode.id === id) {
        value = subItem;
      }
      // 如果是初始节点就不进行操作了
      if (selectDomMap.value.has(id)) {
        // 已经被合并的就不加上去了
        // 还需要转换合并后的宽度
        // 同行合并宽度
        if (row == targetNode.row) {
          value.style.width = getValue(value.style.width, width);
          value.colSpan += colSpan;
        }
        // 同列合并高度
        if (column == targetNode.column) {
          value.style.height = getValue(value.style.height, height);
          value.rowSpan += rowSpan;
        }
      } else {
        return subItem;
      }
    });
  }
  // 合并单元格
  resSetXY();
};

实现HTML导出为Excel

npm i xlsx
npm i file-saver

通过如上的两个组件进行的excel导出

import { saveAs } from 'file-saver';
import { write, utils } from "xlsx";

export default function () {
  // 导出excel
  function exportExcel(Dom: any) {
    let et = utils.table_to_book(
      Dom
  ); //此处传入table的DOM节点
  let etout = write(et, {
      bookType: "xlsx",
      bookSST: true,
      type: "array"
  });
  try {
      saveAs(
          new Blob([etout], {
              type: "application/octet-stream"
          }),
          "自定义表格.xlsx"
      ); //trade-publish.xlsx 为导出的文件名
  } catch (e) {
      console.log(e, etout);
  }
  return etout;
  }
  return {
    exportExcel,
  };
}

当然,这里的 Dom 数组,其实就是我们之前生成的 tableValue 数据