前端表格数据导出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`);
}

三、感谢

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

有问题私信我!!~~

相关推荐
哟哟耶耶1 小时前
Starting again-02
开发语言·前端·javascript
Apifox.1 小时前
Apifox 9 月更新| AI 生成接口测试用例、在线文档调试能力全面升级、内置更多 HTTP 状态码、支持将目录转换为模块
前端·人工智能·后端·http·ai·测试用例·postman
Kitasan Burakku1 小时前
Typescript return type
前端·javascript·typescript
叁佰万1 小时前
前端实战开发(一):从参数优化到布局通信的全流程解决方案
前端
笔尖的记忆2 小时前
js异步任务你都知道了吗?
前端·面试
光影少年2 小时前
react生态
前端·react.js·前端框架
golang学习记2 小时前
从0死磕全栈之Next.js 中的错误处理机制详解(App Router)
前端
力Mer2 小时前
console.log()控制台异步打印与对象展开后不一致问题
前端·javascript
WillaWang2 小时前
Liquid:在assign定义变量时使用allow_false
前端
2401_831501732 小时前
Python学习之Day05学习(定制数据对象,面向对象)
前端·python·学习