使用js 您所在的位置:网站首页 重工业对环境的污染 使用js

使用js

2023-08-08 09:45| 来源: 网络整理| 查看: 265

前言

最近公司需要将几张统计表格导出到excel,由于公司现有导出excel功能是前后端配合的导出,觉得麻烦,所以想找一个纯前端导出的工具,最后找到了js-xlsx,评价还是挺高的,但是中文文档没找到,百度也没有找到一个比较全面的教程,所以踩了很多坑,自己记录下,方便以后使用。

环境

由于我业务只用到将table标签内的内容导出到excel,所以只会写如何将一个table元素里的内容导出到excel。也可以通过json导出,貌似还会更简单些。

安装

GitHub地址 npm安装

npm install xlsx

安装后dist文件夹下有一个文件xlsx.full.min.js,就是它了,引入到项目中

第一个例子

先上代码

Document 序号 姓名 年龄 兴趣 1 张三 18 打游戏 2 李四 88 看电影 3 王五 81 睡觉 导出 function btn_export() { var table1 = document.querySelector("#table1"); var sheet = XLSX.utils.table_to_sheet(table1);//将一个table对象转换成一个sheet对象 openDownloadDialog(sheet2blob(sheet),'下载.xlsx'); }

运行效果 这是个运行效果

导出结果:

在这里插入图片描述 你可能注意到了,我这里引入了一个export.js文件,这个export.js文件里面只有2个方法,就是上面代码用到的openDownloadDialog(sheet2blob(sheet),‘下载.xlsx’); 这是export.js的代码:

// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载 function sheet2blob(sheet, sheetName) { sheetName = sheetName || 'sheet1'; var workbook = { SheetNames: [sheetName], Sheets: {} }; workbook.Sheets[sheetName] = sheet; // 生成excel的配置项 var wopts = { bookType: 'xlsx', // 要生成的文件类型 bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性 type: 'binary' }; var wbout = XLSX.write(workbook, wopts); var blob = new Blob([s2ab(wbout)], { type: "application/octet-stream" }); // 字符串转ArrayBuffer function s2ab(s) { var buf = new ArrayBuffer(s.length); var view = new Uint8Array(buf); for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; return buf; } return blob; } function openDownloadDialog(url, saveName) { if (typeof url == 'object' && url instanceof Blob) { url = URL.createObjectURL(url); // 创建blob地址 } var aLink = document.createElement('a'); aLink.href = url; aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效 var event; if (window.MouseEvent) event = new MouseEvent('click'); else { event = document.createEvent('MouseEvents'); event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); } aLink.dispatchEvent(event); }

PS: 这2个方法是网上当的,原文地址。作者写的挺好,也是从这里找到了头绪。

如果你的table标签内有合并单元格的操作,XLSX.utils.table_to_sheet(*)也能够读取出来,并且你打印出来的结果也能够显示出来,效果图: 在这里插入图片描述 在这里插入图片描述 可以看到,excel中的表格也已经合并了。 但是实际的情况,客户觉得这行字没有居中,他就会向你唠叨,为啥不居中,所以我们现在解决文字不居中的问题。

设置样式(居中,文字大小颜色,背景色…) PS:这是我踩坑最多的地方…

这里就不绕圈子了,设置样式的话,上面的xlsx.full.min.js是无法生效的, 必须安装xlsx-style

安装xlsx-style

好像只有npm安装,github我没找到地址

npm install xlsx-style

同样,安装目录下dist文件夹下有一个xlsx.full.min.js,嗯?名字一模一样?怎么用?好吧,无从下手,只好硬着头皮引入了,注意,我将xlsx-style的js文件放在下方: 在这里插入图片描述 还有btn_export()方法要变一下,加一下样式。 具体的单元格样式说明可以看下这篇文章 xlsx-style单元格样式参考表

function btn_export() { var table1 = document.querySelector("#table1"); var sheet = XLSX.utils.table_to_sheet(table1); //这个就是修改格式的代码 sheet["A5"].s = { font: { sz: 13, bold: true, }, alignment: { horizontal: "center", vertical: "center", wrap_text: true } }; openDownloadDialog(sheet2blob(sheet),'下载.xlsx'); }

改完之后,点击运行,果不其然,报错了: 在这里插入图片描述

原因是什么呢,原因是2个js文件暴露出来的变量都叫‘XLSX’,但是xlsx-style这个js文件里没有XLSX.utils这个方法,而且xlsx-style这个js文件是后引入的,就把前面的XLSX给覆盖了,所以报错。 XLSX.utils里面有很多可用的方法,但是按照这种方式无法进行调用: 在这里插入图片描述 你可能想到把2个js文件调换一下位置,但是结果是xlsx暴露的变量覆盖了xlsx-style暴露的变量。你的样式还是改变不了。

注意 如果你的导出功能 是传入json格式或其他格式而没有用到XLSX.utils的话,你只需使用xlsx-style的js,下面的内容可以忽略,下面的内容是讲如何使xlsx和xlsx-style的js一起工作的。

不用XLSX.utils的方式

由于这2个js都是加密之后的内容,无法解读,不能在这2个js上找到什么有用的东西。好在在xlsx dist文件夹下找到了xlsx.extendscript.js,看这个文件就像个工具类,由于我上面用到了table_to_sheet方法,在xlsx.extendscript上面的搜索了一下,果然发现了这个方法,二话不说,将xlsx的js引用删除,引入xlsx.extendscript: 在这里插入图片描述

运行。结果你应该已经猜到了,样式并没有发生改变。什么原因呢,xlsx.extendscript.js暴露出来的变量仍然是’XLSX’,下面的变量还是覆盖了上面的变量。

注意!!! 如果你的项目中使用了webpack或其他打包工具,可以直接import,不用改变变量名

好在这个xlsx.extendscript.js不是压缩版本,可以对内容进行修改,就把暴露出来的变量修改为’XLSX2’吧。这样我们只有在使用utils工具的时候才用到xlsx.extendscript.js,其余都用的是xlsx-style这个js,这样总该可以了吧 。 修改完之后别忘了将XSLX.utils.table_to_sheet()改成XLSX2.utils.table_to_sheet()。 (不建议修改源码,由于工作需要不修改源码无法使用才做的修改)

function btn_export() { var table1 = document.querySelector("#table1"); var sheet = XLSX2.utils.table_to_sheet(table1); sheet["A5"].s = { font: { sz: 13, bold: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true } }; openDownloadDialog(sheet2blob(sheet), '下载.xlsx'); }

运行: 在这里插入图片描述

可以看到,你所做的样式更改已经生效了。 客户需求增加:我想要前面几行空出来,并且写上打印公司名。 观察xlsx.extendscript.js源码,发现table_to_sheet,也就是parse_dom_table,并没有设置起始行的参数,下面给出parse_dom_table的代码:

function parse_dom_table(table, _opts) { var opts = _opts || {}; if(DENSE != null) opts.dense = DENSE; var ws = opts.dense ? ([]) : ({}); var rows = table.getElementsByTagName('tr'); var sheetRows = opts.sheetRows || 10000000; var range = {s:{r:0,c:0},e:{r:0,c:0}}; var merges = [], midx = 0; var rowinfo = []; var _R = 0, R = 0, _C, C, RS, CS; for(; _R if (opts.display) continue; rowinfo[R] = {hidden: true}; } var elts = (row.children); for(_C = C = 0; _C var m = merges[midx]; if(m.s.c == C && m.s.r s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); var o = {t:'s', v:v}; var _t = elt.getAttribute("t") || ""; if(v != null) { if(v.length == 0) o.t = _t || 'z'; else if(opts.raw || v.trim().length == 0 || _t == "s"){} else if(v === 'TRUE') o = {t:'b', v:true}; else if(v === 'FALSE') o = {t:'b', v:false}; else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)}; else if(!isNaN(fuzzydate(v).getDate())) { o = ({t:'d', v:parseDate(v)}); if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}); o.z = opts.dateNF || SSF._table[14]; } } if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; } else ws[encode_cell({c:C, r:R})] = o; if(range.e.c = sheetRows) ws['!fullref'] = encode_range((range.e.r = rows.length-_R+R-1,range)); // We can count the real number of rows to parse but we don't to improve the performance return ws; }

那自己加一个吧 可以看到,里面的R变量 这是控制起始行的关键所在,好吧,我们再做一下修改:

var _R = 0, R = _opts.rowIndex || 0, _C, C, RS, CS;

这里我们给_opts增加一个属性rowIndex,在调用table_to_sheet方法的时候传入这个属性。下面是变更后的代码:

function btn_export() { var table1 = document.querySelector("#table1"); var opt = { rowIndex: 4 }; //开头空4行 var sheet = XLSX2.utils.table_to_sheet(table1, opt); sheet["A1"] = { t: "s", v: '三鹿集团有限公司' }; //给A1单元格赋值 sheet["A1"].s = { font: { name: '宋体', sz: 24, bold: true, underline: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true }, fill: { bgColor: { rgb: 'ffff00' } } }; //["!merges"]这个属性是专门用来进行单元格合并的 sheet["!merges"].push({//如果不为空push 为空 = 赋值 //合并单元格 index都从0开始 s: { //s开始 c: 0, //开始列 r: 0 //开始行 }, e: { //e结束 c: 3, //结束列 r: 2 //结束行 } }); sheet["A9"].s = { //样式 font: { sz: 13, bold: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true } }; openDownloadDialog(sheet2blob(sheet), '下载.xlsx'); }

运行结果: 在这里插入图片描述 可以看到,你所做的更改生效了。

客户又提新需求了,要加上2个字段,身份证号和手机号。 这还不简单?加上2个字段不就好了。2分钟搞定,导出: 在这里插入图片描述 ??? 身份证号怎么变成了科学计数法,什么鬼(后来发现百分比也会直接给你换算成0~1的小数,统计没法搞) 怎么回事?还是parse_dom_table的杰作! 注意这一行:

else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};

意思是只要从td的text里读取到的值,只要转换之后是一个number,(不管你是string类型),都会给你来一个fuzzynum(v),转换成一个number类型。 做下修改,结果:

function parse_dom_table(table, _opts) { var opts = _opts || {}; if(DENSE != null) opts.dense = DENSE; var ws = opts.dense ? ([]) : ({}); var rows = table.getElementsByTagName('tr'); var sheetRows = opts.sheetRows || 10000000; var range = {s:{r:0,c:0},e:{r:0,c:0}}; var merges = [], midx = 0; var rowinfo = []; var _R = 0, R = _opts.rowIndex || 0, _C, C, RS, CS; for(; _R if (opts.display) continue; rowinfo[R] = {hidden: true}; } var elts = (row.children); for(_C = C = 0; _C var m = merges[midx]; if(m.s.c == C && m.s.r s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}}); var o = {t:'s', v:v}; var _t = elt.getAttribute("t") || ""; if(v != null) { if(v.length == 0) o.t = _t || 'z'; else if(opts.raw || v.trim().length == 0 || _t == "s"){} else if(v === 'TRUE') o = {t:'b', v:true}; else if(v === 'FALSE') o = {t:'b', v:false}; //else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)}; else if(!isNaN(fuzzynum(v))) o = {t:'s', v:v};//不自动格式化number类型 else if(!isNaN(fuzzydate(v).getDate())) { o = ({t:'d', v:parseDate(v)}); if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}); o.z = opts.dateNF || SSF._table[14]; } } if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; } else ws[encode_cell({c:C, r:R})] = o; if(range.e.c = sheetRows) ws['!fullref'] = encode_range((range.e.r = rows.length-_R+R-1,range)); // We can count the real number of rows to parse but we don't to improve the performance return ws; }

将转换的语句注释掉,重写这行代码,如果是number类型,不做任何修改,该是什么值还是什么值。 现在再重新运行,结果: 在这里插入图片描述可以看到,数字能够正常显示了。但是这个单元格好像并不会自动展开,永远都这么大,xlsx-style 也提供了控制单元格宽度的方法:

sheet["!cols"] = [{ wpx: 70 }, { wpx: 70 }, { wpx: 70 }, { wpx: 70 }, { wpx: 150 }, { wpx: 120 }]; //单元格列宽

注意,设置单元格列宽要从第一行开始设置 结果: 在这里插入图片描述 完整前端代码:

Document 序号 姓名 年龄 兴趣 身份证号 手机号 1 张三 18 打游戏 320322184087562589 1374569821 2 李四 88 看电影 420322184087562589 2374569821 3 王五 81 睡觉 520322184087562589 3374569821 这是一个合并单元格 导出 function btn_export() { var table1 = document.querySelector("#table1"); var opt = { rowIndex: 4 }; //开头空4行 var sheet = XLSX2.utils.table_to_sheet(table1, opt); sheet["A1"] = { t: "s", v: '三鹿集团有限公司' }; //给A1单元格赋值 sheet["A1"].s = { font: { name: '宋体', sz: 24, bold: true, underline: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true }, fill: { bgColor: { rgb: 'ffff00' } } }; //["!merges"]这个属性是专门用来进行单元格合并的 sheet["!merges"].push({ //如果不为空push 为空 = 赋值 //合并单元格 index都从0开始 s: { //s开始 c: 0, //开始列 r: 0 //开始行 }, e: { //e结束 c: 3, //结束列 r: 2 //结束行 } }); sheet["A9"].s = { //样式 font: { sz: 13, bold: true, color: { rgb: "FFFFAA00" } }, alignment: { horizontal: "center", vertical: "center", wrap_text: true } }; sheet["!cols"] = [{ wpx: 70 }, { wpx: 70 }, { wpx: 70 }, { wpx: 70 }, { wpx: 150 }, { wpx: 120 }]; //单元格列宽 openDownloadDialog(sheet2blob(sheet), '下载.xlsx'); } demo源码

csdn下载 完整实例 由于csdn积分制度递增,无法控制,所以贴上github地址 完整实例

总结 不是特殊情况不建议修改源码因为毕竟修改了代码,所以这种方法只能面向小众听过收费版功能很全,建议如果有需要的话还是购买收费版本,但是地址没找到…可以根据自己需求对xlsx源码进行修改,以便满足自己工作的需求。但是这样较难以维护,如何取舍还是自行斟酌。我这里只列取了我实际工作中所需要的功能,xlsx的功能很丰富,有空可以多琢磨琢磨。


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有