首页 > 其他分享 >前端导出 Excel

前端导出 Excel

时间:2023-05-28 14:11:07浏览次数:49  
标签:xlsx style const Excel 前端 导出 jsonWorkSheet data

需求背景

在项目开发中遇到需要前端将后端返回的数据导出的任务,由于后端已经全部返回了相关数据,为避免重复请求接口、减少后端IO提升系统性能,因此需要在前端将后端返回的任务数据导出成 Excel。之前没有做过前端根据数据直接导出excel的案例,特此做记录。

使用的插件

  1. xlsx 用于解析和编写各种电子表格的前端 JavaScript 库。xlsx文档
  2. xlsx-style 用于为 xlsx 库添加样式,比如字体颜色,大小,行宽等。但是只支持xlsx、xlsm、xlsb格式。
  3. FileSaver.js 负责下载保存文件。对各种兼容性比较好,对跨域文件也有处理。
  4. lodash js 常用工具库。

遇到的问题

一、引入 xlsx-style 报错

This relative module was not found: 
./cptable in ./node_modules/[email protected]@xlsx-style/dist/cpexcel.js

解决方案:在 vue.config.js中添加下面配置:

chainWebpack: config => {
  config.externals({ './cptable': 'var cptable' })
}

二、样式设置问题

  1. xlsx-style 只支持 16 进制的 rgb 颜色,比如 { rgb: 'ff0000' }。注意这里是没有 # 号的。
  2. 添加背景色是使用 fill 的 fgColor,而不是 bgColor。这里需要驼峰编写。

三、使用 xlsx 方法时报错
使用 XLSX.utils.json_to_sheet方法将 json 转成 workSheet 对象时报错

"TypeError: Cannot read properties of undefined (reading 'utils')"

xlsx.js 库不是 默认 导出,而是将所有方法属性单个导出,因此导入时应该是:

import * as XLSX from 'xlsx';
// 或者
import { utils } from 'xlsx';

四、引入 path 和 fs 模块报错

/// 首先安装 npm install node-polyfill-webpack-plugin -S

const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')

transpileDependencies: true,
configureWebpack: {
    // 引入 NodePolyfillPlugin 使 es6 模块可以引入 common.js 模块,webpack5以上需要手动安装
    plugins: [new NodePolyfillPlugin()],
    // 禁用 fs 模块
    resolve: { fallback: { fs: false } }
  },

实现步骤

说明:xlsx 可以使用获取表格 DOM 的方式将 DOM 转换为 xlsx workbook,但由于当前表格实现多是虚拟滚动或者分页实现的,所以这种方式虽然简单但并不能很好实现预期目标。因此本文略过这种实现方案。

基础版本

直接使用 xlsx 一个库实现导出excel,没有样式。

/**
* @description 基础版本
*/
downloadExcel (array, sheetName , fileName) {
  const header = ['date', 'name', 'address'];
  const header_zh = { date: '日期', name: '姓名', address: '地址' };

  const jsonWorkSheet = XLSX.utils.json_to_sheet(
    [header_zh, ...array],
    {
      header: header,
      skipHeader: true
    }
  );
  const workBook = {
    SheetNames: [sheetName],
    Sheets: {
      [sheetName]: jsonWorkSheet
    }
  }
  return XLSX.writeFile(workBook, fileName)
},

导出效果如下:

带样式版本

使用 xlsx 的 json_to_sheet 工具方法,把数组的数据格式转换成 xlsx 需要 worksheet。然后再添加 xlsx-style 支持的样式代码,使用 xlsx-style 编写成数据流,最后再使用 FileSaver.js 把数据流保存成文件。

  1. 创建工作簿和表头
// 创建工作簿
const workBook = XLSX.utils.book_new();
// 显示表头, 只包含表头的表格
const jsonWorkSheet = XLSX.utils.json_to_sheet(
  // [colNames, ...data],
  [colNames],
  {
    header: keys,
    skipHeader: true
  }
)
  1. 追加表格实际要导出的数据
// 追加数据到excel中,从第二行开始
XLSX.utils.sheet_add_json(jsonWorkSheet, data, { header: keys, skipHeader: true, origin: 'A2' })
  1. 设置表格样式
let workBookOut;
for (const key in jsonWorkSheet) {
  // 获取第一行数据,设置对应的样式
  if (key.replace(/[^0-9]/ig, '') === '1') {
    jsonWorkSheet[key].s = style.hs;
  } else {
    // 非A-Za-z结尾的字符串将会被替换为空,最后结果结尾的一定是A-Za-z
    let keyStr = key.replace(/[^A-Za-z]+$/ig, '')
    // 全是 A-Za-z,避免!ref !cols !rows属性
    const reg = /^[A-Za-z]+$/
    if (reg.test(keyStr)) {
      jsonWorkSheet[key].s = style.bs;
    }
  }
}
// 表格列样式
jsonWorkSheet['!cols'] = colsParams;
  1. 生成导出流,下载文件
// 二进制流
workBookOut = XLSXStyle.write(workBook, { bookType: bookType, bookSST: false, type: 'binary' });
saveAs(new Blob([workBook2ArrayBuffer(workBookOut)], { type: '' }), filename);
  1. 完整代码
import * as XLSX from 'xlsx';
import XLSXStyle from 'xlsx-style';
import { saveAs } from 'file-saver'
import path from 'path';
import _ from 'lodash';

// 默认文件名
const FILE_NAME = '数据导出表.xlsx';
// 列属性支持的配置字段
const COL_PARAMS = ['hidden', 'wpx', 'width', 'wch', 'MDW'];
// 表格样式
const TABLE_STYlE = {
  // 表头样式
  hs: {
    font: { sz: 10, color: { rgb: "000000" }, bold: true },
    alignment: { horizontal: "center", vertical: "center", wrapText: true },
    fill: { bgColor: { indexed: 64 }, fgColor: { rgb: "FFFF00" } },
    border: { bottom: { style: 'thin', color: '000000' }, right: { style: 'thin', color: '000000' } }
  },
  // 内容样式
  bs: {
    font: { sz: 11 },
    alignment: { horizontal: "center", vertical: "center", wrapText: true },
    border: { bottom: { style: 'thin', color: '000000' }, right: { style: 'thin', color: '000000' } }
  },
};

/**
 * worksheet转成ArrayBuffer
 * @param { jsonWorkSheet } jsonWorkSheet xlsx库中的worksheet
 */
function workBook2ArrayBuffer(jsonWorkSheet) {
  const buffer = new ArrayBuffer(jsonWorkSheet.length);
  const view = new Uint8Array(buffer);
  for (let i = 0; i !== jsonWorkSheet.length; ++i) {
    view[i] = jsonWorkSheet.charCodeAt(i) & 0xFF;
  }
  return buffer;
}

/**
 * 导出成Excel
 * @param {Array} data 数据
 * @param {Object} columns 表格columns,用于获取 keys, colNames, 列宽属性
 * @param {String} filename 文件名。支持:'.xlsx', '.xlsm', '.xlsb', '.csv'
 */
export function exportExcel(data, columns, filename = FILE_NAME, style = TABLE_STYlE) {
  if (!data?.length || !columns?.length) {
    return console.error('data或colums不存在无法导出');
  }

  // 根据不同的扩展名,导出不同格式的文件
  let bookType = null;
  let ext = path.extname(filename);
  if (!ext) {
    filename += '.xlsx';
    bookType = 'xlsx';
  } else if (!['.xlsx', '.xlsm', '.xlsb', '.csv'].includes(ext)) {
    return console.error(`不支持导出${ext}格式的文件`);
  } else {
    bookType = ext.substring(1).toLowerCase();
  }
  // data 字段key
  const keys = [];
  // 表格列字段对象
  const colNames = {};
  // 设置列宽属性
  const colsParams = [];

  columns.forEach(column => {
    if (!column?.type) {
      keys.push(column.field);
      colNames[column.field] = column.label;

      let param = {};
      COL_PARAMS.forEach(item => {
        if (column?.exportParams[item]) {
          param[item] = column.exportParams[item];
        }
      })
      colsParams.push(param);
    }
  })

  // 创建工作簿
  const workBook = XLSX.utils.book_new();

  // 显示表头, 只包含表头的表格
  const jsonWorkSheet = XLSX.utils.json_to_sheet(
    // [colNames, ...data],
    [colNames],
    {
      header: keys,
      skipHeader: true
    }
  )

  // 过滤数据,只显示表头包含的数据
  for (let i = 0; i < data.length; i++) {
    // loadsh pick方法:根据keys,返回一个新数组
    data[i] = _.pick(data[i], keys);
  }

  // 追加数据到excel中,从第二行开始
  XLSX.utils.sheet_add_json(jsonWorkSheet, data, { header: keys, skipHeader: true, origin: 'A2' })
  const sheetName = filename.split('.')[0];
  workBook.SheetNames.push(sheetName);
  workBook.Sheets[sheetName] = jsonWorkSheet;

  let workBookOut;
  for (const key in jsonWorkSheet) {
    // 获取第一行数据,设置对应的样式
    if (key.replace(/[^0-9]/ig, '') === '1') {
      jsonWorkSheet[key].s = style.hs;
    } else {
      // 非A-Za-z结尾的字符串将会被替换为空,最后结果结尾的一定是A-Za-z
      let keyStr = key.replace(/[^A-Za-z]+$/ig, '')
      // 全是 A-Za-z,避免!ref !cols !rows属性
      const reg = /^[A-Za-z]+$/
      if (reg.test(keyStr)) {
        jsonWorkSheet[key].s = style.bs;
      }
    }
  }
  // 表格列样式
  jsonWorkSheet['!cols'] = colsParams;
  // 二进制流
  workBookOut = XLSXStyle.write(workBook, { bookType: bookType, bookSST: false, type: 'binary' });

  saveAs(new Blob([workBook2ArrayBuffer(workBookOut)], { type: '' }), filename);
}

总结

本文介绍了前端使用 xlsx 插件实现下载功能的案例, 通过 xlsx 库结合 xlsx-style 和 fileSaver 可以根据后端返回的数据由前端实现导出表格并设置样式的需求。

参考文章

  1. xlsx.js 表格的导出与导入
  2. js xlsx自定义样式导出
  3. xlsx文档

标签:xlsx,style,const,Excel,前端,导出,jsonWorkSheet,data
From: https://www.cnblogs.com/aurora-ql/p/17438192.html

相关文章

  • RefsUtil 是 Windows 下一款用于管理 REFS 文件系统的实用工具,它提供了丰富的功能和命
    RefsUtil是Windows下一款用于管理REFS文件系统的实用工具,它提供了丰富的功能和命令行界面,可用于创建、修改、检查和修复REFS分区,以及导出和导入数据等操作。以下是一些使用RefsUtil工具的示例:创建REFS分区要创建一个新的REFS分区,可以使用以下命令:CopyCoderef......
  • 前端HTML标签1
    HTML实用合集11.框架使用英文!,按tab键出现框架。2.改标题<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname=&q......
  • Java语言实现的springBoot汽车销售管理系统vue前端
    技术架构技术框架:springboot+mybatis+Mysql5.7+vue2+npm+node运行环境:jdk8+IntelliJIDEA+maven+宝塔面板宝塔部署教程解析一个域名,使用vscode打开front目录,修改/config/prod.env.js文件里的BASE_API字段为解析好的线上域名,执行npmrunbuild:prod打包出......
  • XXX项目前端开发样式统一规范
    前端开发样式规范参考资料:https://element.eleme.cn/#/zh-CN/component/form规范1:报错提示统一用浅红色,成功提示为绿色,警告性提示为橙色规范2: 页面有多个必填字段未填写,一次性提示,同时填写文本框爆红,文本框下方有红字提醒红字提醒可按需展示,本文框间距有限,红字展示可能......
  • 非Teams会议组织者如何导出参会列表
    需求背景通常来说,只有会议的组织者才能够从Teams客户端导出Teams会议的参会人列表,或者需要Teams管理员从后台导出。而在某些情况下,需要非Teams会议组织者协助导出次列表,那么我们可以使用Teams会议的共同组织者(Co-organizer)功能来实现这个需求。概念解释邀请他人参加会议后,您最多......
  • 自定义导出Excel表列数据(根据所选的列,选几列导出几列数据,不选则全部导出)
       ......
  • 我的第一个项目(十四) :完成数据保存功能(前端,增查改接口)
    好家伙,天天拖,终于写完了 代码已开源(Gitee)PH-planewar:个人开发的全栈小游戏前端:vue2+element-ui后端:Springboot+mybatis-plus数据库:mysql目前实现功能:1.注册登陆2.游戏数据保存3.游戏运行(gitee.com)(前后端放一起了)怎么说呢,感觉比较简洁,但是问题......
  • solidworks vba 导出数据到文本文件
    Thismacroexportsalltheinformationintotheoutputtextfileinthefollowingformat:OptionExplicitConstcurrentDirAsString="D:\"'DimswAppAsSldWorks.SldWorksSubmain()DimfilePathAsStringfilePath=currentDi......
  • expdp 导出缓慢
    expdp导出缓慢查询等待事件,目前导出的等待事件是:selectinst_id,sql_id,event,count(*)fromgv$sessionwherewait_class<>'Idle'groupbyinst_id,sql_id,eventorderbycount(*)desc;INST_IDEVENTCOUNT(1)---------......
  • Web 前端常用正则校验规则
    Web前端常用正则校验规则作为Web前端开发,常用的正则校验规则有很多。下面是一些常见的示例:校验手机号码手机号码的正则表达式可以根据不同国家和地区的手机号码格式进行调整。以下是中国大陆的手机号码正则表达式:constregex=/^1[3456789]\d{9}$/;在这个示例中,正则表......