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

三、感谢

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

有问题私信我!!~~

相关推荐
dancehole2 分钟前
嘉为科技 前端实习 面经(OC)
前端·科技
Cutey9169 分钟前
H5页面嵌入项目的完整方案
前端·javascript·面试
凌冰_9 分钟前
Vscode HTML5新增元素及属性
前端·html·html5
阿丽塔~19 分钟前
react中 useEffect和useLayoutEffect的区别
前端·react.js·前端框架
飘尘31 分钟前
春天来了,来生成一棵独属自己的花树吧!
前端·javascript·canvas
旺代32 分钟前
CSS圣杯布局与双飞翼布局
前端·css
dchen7735 分钟前
前端实现大文件下载的终极解决方案!!!
前端·javascript·面试
ak啊36 分钟前
Webpack启动流程与初始化-Tapable 事件流机制
前端·webpack·源码
巴巴博一37 分钟前
Vue-admin-template安装教程
前端·javascript·vue.js
前端菜鸟来报道1 小时前
html和css 实现元素顺时针旋转效果(椭圆形旋转轨迹)
前端·css·旋转·椭圆布局