利用xlsx-syle前端导出excel且支持自定义样式

前言

本文的代码是基于react的。

本文仅用于记录我在前端导出excel遇到的问题的笔记整理。

需求描述

需要前端来实现对数据的导出,导出成excel格式。

excel打开后的样式要符合需求图

需求图:

导出1.png

前期解决过程

我在网上找到前端用于导出的插件js-xlsx,按照操作说明鼓捣完成后导出excel的样子只是最基础的模板

导出2.png

当我想进一步去修改样式,让他达到需求那样,结果发现xlsx插件开源版不支持修改excel的样式,需要付费版才有支持功能,然而付费要700美元,果断放弃。

后来我找到了xlsx-style插件可以代替,它支持修改样式且是免费的。

中期解决过程

然而xlsx-style插件不像js-xlsx插件那样乖巧,在安装和引入阶段也会有各种问题

import引入xlsx-stle时一般都会报错:This relative module was not found: ./cptable in ./node_modules/xlsx-style@0.8.13@xlsx-style/dist/cpexcel.js

这个问题需要去修改xlsx-style插件里的源码,即要改动node_modules文件夹。

然而对于非本地demo的项目来说,node_modules因是存放依赖的,且很大,代码提交或上传时都会忽略node_modules,需要使用时才会安装依赖,就算改动xlsx-style的源码,依赖重新安装后也会被覆盖掉。

这个问题可以藉由将这个依赖的代码从node_modules拿出来放在项目里,在最外层index.html里引入即可。

然而对于高版本的Hzero,最外层的index.html文件被隐藏了,无法引入,需要把node_modules/hzero-boot/public/index.html的index.html文件复制到外层public文件夹下,才可以使用。

此时xlsx-style插件已经全局引入了,可以开始写导出功能了。

导出功能的代码

导出的方法

function saveAs(obj, fileName) {

const tmpa = document.createElement('a');

tmpa.download = fileName || '未命名';

// 兼容ie

if ('msSaveOrOpenBlob' in navigator) {

window.navigator.msSaveOrOpenBlob(obj, '下载的文件名' + '.xlsx');

} else {

tmpa.href = URL.createObjectURL(obj);

}

tmpa.click();

setTimeout(function() {

URL.revokeObjectURL(obj);

}, 100);

}

function s2ab(s) {

if (typeof ArrayBuffer !== 'undefined') {

const buf = new ArrayBuffer(s.length);

const view = new Uint8Array(buf);

for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;

return buf;

} else {

const buf = new Array(s.length);

for (let i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff;

return buf;

}

}

// 获取26个英文字母用来表示excel的列

function getCharCol(n) {

const temCol = '';

let s = '';

let m = 0;

while (n > 0) {

m = (n % 26) + 1;

s = String.fromCharCode(m + 64) + s;

n = (n - m) / 26;

}

return s;

}

function downloadExl(json, type, options) {

var tmpdata = json[0];

// 定制化改动地方

json.unshift({}, {}, {}, {}); // 向表格数据中插入4行位置(标题和参数)

const keyMap = []; // 获取keys

for (const k in tmpdata) { // 为插入的4行位置添加数据

keyMap.push(k);

// 定制化改动地方

json[3][k] = k; // json[3][k] = k 3为插入4行的最后一行索引,用于展示列头

}

var tmpdata = []; // 用来保存转换好的json

json

.map((v, i) => {

const data = keyMap.map((k, j) => {

return Object.assign(

{},

{

v: v[k],

position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 2), // 表格数据的位置

}

);

});

return data;

})

.reduce((prev, next) => prev.concat(next))

.forEach(

(v, i) =>

(tmpdata[v.position] = {

v: v.v,

})

);

let outputPos = Object.keys(tmpdata); // 设置区域,比如表格从A1到D10

// 定制化改动地方

tmpdata.A1 = { v: options.dataTitle }; // A1-A4区域的内容

tmpdata.A2 = { v: options.reportCompany };

tmpdata.A3 = { v: options.date };

tmpdata.A4 = { v: options.reportType };

// 定制化改动地方

outputPos = ['A1'].concat(['A2'], ['A3'], ['A4'], outputPos);

// 定制化改动地方

tmpdata.A1.s = {

font: { sz: 14, bold: true, vertAlign: true },

alignment: { vertical: 'center', horizontal: 'center' }, // 垂直、水平

fill: { bgColor: { rgb: 'E8E8E8' }, fgColor: { rgb: 'E8E8E8' } },

}; // <====设置xlsx单元格样式

tmpdata.A2.s = {

font: { sz: 12, bold: true, vertAlign: true },

alignment: { vertical: 'center', horizontal: 'bottom' },

}; // <====设置xlsx单元格样式

tmpdata.A3.s = {

font: { sz: 12, bold: true, vertAlign: true },

alignment: { vertical: 'center', horizontal: 'bottom' },

}; // <====设置xlsx单元格样式

tmpdata.A4.s = {

font: { sz: 12, bold: true, vertAlign: true },

alignment: { vertical: 'center', horizontal: 'bottom' },

}; // <====设置xlsx单元格样式

// s-e 代表区域 c-r 代表列-行的索引

// 定制化改动地方

tmpdata['!merges'] = [

{

s: { c: 0, r: 0 },

e: { c: 3, r: 0 },

},

{

s: { c: 0, r: 1 },

e: { c: 3, r: 1 },

},

{

s: { c: 0, r: 2 },

e: { c: 3, r: 2 },

},

{

s: { c: 0, r: 3 },

e: { c: 3, r: 3 },

},

]; // <====合并单元格

let dataArrWidth = []

// 定制化改动地方

json.forEach(item => {

dataArrWidth.push({ wpx: 100 })

})

tmpdata['!cols'] = dataArrWidth;// <====设置一列宽度, 代表20列都是300宽

const tmpWB = {

SheetNames: ['mySheet'], // 保存的表标题

Sheets: {

mySheet: Object.assign(

{},

tmpdata, // 内容

{

'!ref': `${outputPos[0]}:${outputPos[outputPos.length - 1]}`, // 设置填充区域(表格渲染区域)

}

),

},

};

const tmpDown = new Blob(

[

s2ab(

XLSX.write(

tmpWB,

{ bookType: type == undefined ? 'xlsx' : type.bookType, bookSST: false, type: 'binary' } // 这里的数据是用来定义导出的格式类型

)

),

],

{

type: '',

}

);

// 定制化改动地方

saveAs(tmpDown, `${'超合同清账&明细' + '.'}${type.bookType == 'biff2' ? 'xls' : type.bookType}`);

}

function s2ab(s) {

if (typeof ArrayBuffer !== 'undefined') {

const buf = new ArrayBuffer(s.length);

const view = new Uint8Array(buf);

for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;

return buf;

} else {

const buf = new Array(s.length);

for (let i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff;

return buf;

}

}

downloadExl方法里进行excel导出后的样式自定义

所有注释 // 定制化改定地方处即为样式自定义时需要改动的内容,

常用样式处也在代码中进行了注释。

导出方法的使用

function handleClick() {

// 模拟数据

// 定制化改动地方

let data = [];

for (let i = 0; i < 10; i++) {

let obj = {

'合同编号': '移YZ合同[2017]1491号',

'合同所在地市': '扬州',

'合同名称': '扬州分公司与仪征技师学院签订的仪征技师学院室内分布系统合作协议书',

'是否补充协议': '否',

'原合同编号': '',

'原合同名称': '',

'供应商编号': 'MDM_200123316',

'供应商名称': '乐山市中心城区星飞探汽车装饰用品店',

'是否集采': 'PURCHASING_03',

'主执行部门名称': '江苏\扬州\仪征分公司\技术业务支撑中心',

'合同性质': 'SINGLE_CONTRACT',

'合同性质': '单项合同',

'关联类型': '未知',

'收支类型': '',

'相对方类型': '供应商',

'合同状态': 7,

'省公司所在部门': '江苏\扬州\仪征分公司',

'合同总金额': 0,

'调整后合同总金额': '',

'在途支付金额': 0,

'合同累计报账金额': 217158.15,

'合同累计支付金额': 217158.15,

'超付金额=累计支付-合同总金额': 217158.15,

'期初累计报账金额': 91472.7,

'期初累计支付金额': 91472.7,

'总计': 125685.45,

};

data.push(obj);

}

// 表格标题

// 定制化改动地方

const options = {

dataTitle: '超合同清账&明细',

reportCompany: `报账公司: XXX`,

date: `日期: XXXX-XX-XX`,

reportType: `报账单类型: XXX`,

}

// 配置文件类型

const wopts = { bookType: 'xlsx', bookSST: true, type: 'binary', cellStyles: true };

downloadExl(data, wopts, options);

}

options 配置非表格数据的所有内容

然后在downloadExl方法中对options的内容进行样式排版

如此样式不能满足所需,修改 // 定制化改定地方注释处即可,

更多内容可以参考官网文档 https://www.npmjs.com/package/xlsx-style

最后上效果图:

导出3.png

总结

因为时间原因,本文只说了下xlsx-style插件的使用前置和给出了个导出demo的部分代码,其实这个导出还有很多问题没有处理,比如导出20列5W条数据时就会程序崩溃,数据越多导出越慢,理想是1-2万条。导出后的excel中数字不是数字格式,需要手动修改成数字。这个导出功能我现在还只是做了个demo,很多数据都是写死的,等这段时间忙完后,我会抽空把导出功能抽离成组件来更方便使用的

image.png

xlsx模块 前端_利用xlsx-syle前端导出excel且支持自定义样式相关推荐

  1. js-xlsx/xlsx-style 纯前端数据导出Excel且支持自定义样式

    前端开发过程中经常遇到导出excel的需求.这种情况大多数都是服务端处理数据(QAQ至少我遇到的大多数都是这样),然后返回一个链接,前端不需要管服务端怎么操作直接打开这个链接(window.locat ...

  2. python3 根据sql导出excel文件 支持xls和xlsx

    python3 根据sql导出excel文件 支持xls和xlsx 代码简介: sql_output_excel函数是用来导出excel文件的,其他两个函数是导出xls和xlsx格式的. 使用pymy ...

  3. 利用hutool工具类导出Excel

    简单介绍 可以使用hutool工具类,简单的生成Excel.本质上还是使用的POI组件,只是对其进行了封装,避免开发人员重复造轮子 hutool工具类链接 maven导入 <!-- hutool ...

  4. Java 利用hutool工具实现导出excel并合并单元格

    Java 利用hutool工具实现导出excel并合并单元格 controller层调用service,就一个核心方法,没错就下面这个代码就能实现了.前提是项目里面要引用hutool包.把我这个复制到 ...

  5. python关闭excel文件_利用Python读取和修改Excel文件(包括xls文件和xlsx文件)

    本文介绍一下使用Python对Excel文件的基本操作,包括使用xlrd模块读取excel文件,使用xlwt模块将数据写入excel文件,使用openpyxl模块读取写入和修改excel文件. 目录 ...

  6. 爱前端2018全栈大前端_启动2018年前端工具调查

    爱前端2018全栈大前端 by Ashley Watson-Nolan 通过阿什利沃森-诺兰 启动2018年前端工具调查 (Launching the Front-End Tooling Survey ...

  7. excel python插件_利用 Python 插件 xlwings 读写 Excel

    Python 通过 xlwings 读取 Excel 数据 去年底公司让我做设备管理,多次委婉拒绝,最终还是做了.其实我比较喜欢技术.做管理后发现现场没有停机率统计,而原始数据有,每次要自己在Exce ...

  8. js前端导出Excel(可自定义文件名称,后缀,有边框样式)

    需求: 要求把项目中的table表格导出Excel 需求分析及解决: 既然需要导出,是报表的可能性比较大,我的项目中就是这样,那既然是报表导出,可以是前端导出,也可以是后端导出(技术包括POI或者报表 ...

  9. npoi把xlsx文件转为html,C# NPOI 导入与导出Excel文档 兼容xlsx, xls(xf13中已经引用了xlsx的npoi)...

    这里使用的NPOI版本为: 2.1.3.1 版本内包含.Net 2.0 与.Net 4.0 .Net 4.0中包含文件 使用时需引用需要引用所有5个dll 使用到的引用 using NPOI.HSSF ...

最新文章

  1. android预置第三方apk,android 内置APK成系统应用
  2. 【Spark Summit East 2017】Spark化数据引擎
  3. 混合粒子群算法原理通俗讲解
  4. BOOST内存管理(一) --- boost::object_pool
  5. Robot Framework(十七) 扩展RobotFramework框架——扩展Robot Framework Jar
  6. 转)TNS协议--翻译自《The Oracle Hackers Handbook》
  7. 模块一 day09 文件操作相关
  8. Python 做一个属于自己的web网站
  9. 同频共振数据时代,AntDB数据库与永洪科技完成产品互认证
  10. 【虚拟仿真】Unity3D中如何实现让3D模型显示在UI前面
  11. python数据分析-numpy学习
  12. LDAP简介及Java、客户端连接
  13. Alpha选股:资本资产定价模型(CAPM)
  14. 独立视频LED显示屏控制系统
  15. 第一次学习Web的总结
  16. 乔恩·斯凯特(Jon Skeet)-编程的查克·诺里斯(Chuck Norris)
  17. Java程序员面试笔试宝典
  18. Python3飞机大战全代码(亲测OJBK)
  19. 计算机专业竞争力度大吗,求职竞争最激烈十大行业出炉 计算机软件业榜首
  20. 操作系统真象还原——12.初见MBR

热门文章

  1. 【校招VIP】应届生也被裁!如何在校招中站稳脚跟?
  2. python爬虫-爬取盗墓笔记
  3. win10 卡机卡死卡顿的真正原因!
  4. HCL(六)—配置PPP
  5. 几个CPU常见故障分析,如何处理呢
  6. 串行通信接口SCI图解
  7. WAService.js:1 navigateTo:fail page is not found
  8. 淬火系统冷却特性测试仪软件,SQ2-瑞典IVF智能淬火介质冷却特性测试仪
  9. ZCMU--5252: 英雄卡(C语言)
  10. c2664错误c语言,vc10的C2664和C2065错误