前端表格数据导出Excel文件方法,列自适应宽度、增加合计、自定义文件名称

文章目录


前言

开发过程中,后端反馈无法实现导出的Excel表格文件宽度根据数据进行宽度自适应,故实现此方案。

  1. 前端根据返回数据结合表格字头实现导出下载Excel文件,Excel文件每列的宽度根据数据长度进行自适应。
  2. 还可以增加最后一行的 "合计" 数据。
  3. 还可以自定义Excel表格的文件名称。

一、导出效果

二、直接上代码

方法如下:

js 复制代码
/**
 * 表格导出(自适应导出列)
 * params
 *    title: 标题
 *    tableData 表格数据
 *    columns 表头展示列  如:[{ label: '单位名称', prop: 'ZGDWMC' }]
 *    removeProps 导出表格去除列 如 ['ZGDWMC', 'JDJC'] 会过滤掉 ZGDWMC 和 JDJC
 * sumObj
 *  bottomSum 是否需要底部合计
 */
export const adaptiveTableExport = (params = {}, sumObj = { bottomSum: false }) => {
  if(!params.tableData) return console.log('没有表格数据!');
  if(!params.columns) return console.log('没有自定义表头展示列!');
  const excel = XLSX.utils.book_new();
  let demo = [];
  let columns = deepClone(params.columns);
  let tableData = deepClone(params.tableData);
  // 删除去除列
  if(params.removeProps){
    columns = params.columns.filter(item => {
      if(!params.removeProps.includes(item.prop)){
        return item;
      }
    })
  }
  // 判断是否需要合计添加合计列
  if(sumObj.bottomSum && tableData.length > 0){
    let sums = {};
    columns.forEach((column, index) => {
      if (index === 0) {
        sums[columns[index].prop] = '合计';
        return;
      }
      const values = tableData.map(item => Number(item[column.prop]));
      if (!values.every(value => isNaN(value))) {
        sums[columns[index].prop] = values.reduce((prev, curr) => {
          const value = Number(curr);
          if (!isNaN(value)) {
            return prev + curr;
          } else {
            return prev;
          }
        }, 0);
        sums[columns[index].prop] += '';
      } else {
        sums[columns[index].prop] = '0';
      }
    });
    tableData.push(sums);
  }
  // 开始计算
  if(tableData.length > 0){
    for (let i = 0; i < tableData.length; i++) {
      const object = tableData[i];
      let obj = {}
      for (const key in object) {
        if (Object.hasOwnProperty.call(object, key)) {
          for (let index = 0; index < columns.length; index++) {
            const element = columns[index];
            obj[element.label] = String(object[element.prop]) || '  '
          }
        }
      }
      demo.push(obj);
    }
  } else {
    let obj = {};
    for (let index = 0; index < columns.length; index++) {
      const element = columns[index];
      obj[element.label] = element[element.label] || ' ';
    }
    demo.push(obj);
  }
  let data = XLSX.utils.json_to_sheet(demo, {});
  data["A1"].s = {
    font: {
      bold: true,
    },
    alignment: {
      horizontal: "center",
      vertical: "center",
    },
  };
  // 1.所有表头的宽度
  const headsWidth = Object.keys(demo[0]).map((value) => {
    if (/.*[\u4e00-\u9fa5]+.*$/.test(value)) {
      return parseFloat(value.toString().length * 2.1);
    } else {
      return parseFloat(value.toString().length * 1.1)
    }
  });
  // 2.所有表体值的宽度
  const rowsWidth = demo.map((item) => {
    // 每行数据中值的宽度
    const maxValue = Object.values(item).map((value, index) => {
      let valueWidth;
      if (/.*[\u4e00-\u9fa5]+.*$/.test(value)) {
        valueWidth = parseFloat(value.toString().length * 2.1);
      } else {
        if (value) {
          valueWidth = parseFloat(value.toString().length * 1.1);
        }
      }
      // 对比出表头和表体值的最大数
      return Math.max(valueWidth, headsWidth[index]);
    });
    return maxValue;
  })
  // 3.对比每列最大值
  let aotuWidth = []
  rowsWidth.map((row, index) => {
    let maxWidth = [];
    row.map((value, i) => {
      if (index === 0) {
        maxWidth.push({
          wch: value
        });
      } else {
        maxWidth.push({
          wch: Math.max(value, aotuWidth[i].wch)
        })
      }
    })
    aotuWidth = maxWidth;
  });
  // 4.给excel设置自适应宽度
  data["!cols"] = aotuWidth;
  XLSX.utils.book_append_sheet(excel, data);
  XLSX.writeFile(excel, `${ params.title || '自适应表格导出' }.xlsx`);
}

三、感谢

如果觉得有用欢迎点赞关注收藏。

有问题私信我!!~~

相关推荐
普通人62 小时前
php+html+canvas实现树状打开的结构
开发语言·javascript·html5·1024程序员节
梦曦i2 小时前
uni-storage 0.1.0 发布:TTL过期管理+多实例隔离
前端·storage·uni-app x
泡海椒3 小时前
JQuick-Excel 自定义 SPI Provider:用 fullName 扩展 TRANSFORM 函数
驱动开发·excel
猫头_3 小时前
AI 流式传输工程指南:模型吐出半截 JSON,前端如何边收边渲染?
前端·javascript·llm
console.log('npc')4 小时前
第 1 章 项目概述与环境搭建
前端·人工智能·大模型
定栓4 小时前
Webpack迁到Vite第七节(二):全家桶移除 — Babel 全家桶深度分析
前端·webpack·node.js
IT_陈寒4 小时前
React组件莫名重渲染?你可能忘了这个小细节
前端·人工智能·后端
鶴哥只手遮天4 小时前
React 19.3.1 源码深度剖析-第 12 章(下)RSC 与 Flight 协议
前端·react.js·开源
deli0074 小时前
TCP 三次握手到底发几个包?丢包重传动画实测一遍
前端
盟接之桥4 小时前
盟接之桥谈线束数字化-按单入按单出:线束企业库存管理的破局之道
大数据·前端·网络·数据库·人工智能·制造