• 关于js-xlsx的使用


    写在前头,本人是名Java开发人员,偶尔在前端打打酱油,写出的代码或许存在问题,请路过的大神一一指正,不吝感激。

       最近公司准备做一些关于Excel 数据导入和导出相关需求,之前有在开源社区看到说比起纯后端解析,前端更有优势,一来是现在的个人电脑的性能已经有了长足的进步,而来,服务端的资源本就金贵,后端服务的瓶颈就是业务系统平台的瓶颈,对于服务端的优化,本就是一个永久的话题,说到这里,基本上也就该说今天的主角了,js-xlsx。

      要说js-xlsx,就不得不说xlsx,为什么呢,我也是在刚接触是一头雾水,因为在npm上搜索xlsx,第一条就是xlsx,但是进去之后就蒙了,怎么是js-xlsx呢?不信你看看。那在npm上搜索js-xlsx呢,进去之后却看到,xlsx-style,???如果你足够细心的话可能还会看到一个包,那就是xlsx-style,看到这里你估计就该问了,xlsx,js-xlsx,xlsx-style这些都是什么鬼,我说下我的理解吧,这些都是xlsx的分支,只不过由于xlsx的部分功能问题,其他人在xlsx的基础上衍生出了很多版本,比如还未提到的node-xlsx,以及鄙人的sognyz-xlsx,这些都是或多或少的引用了官方代码,在此基础上,进行了扩展开发,至于该怎么用,我说下我的看法,xlsx应该是bug最少也最稳定的,至少人家是鼻祖,关于xlsx-style和js-xlsx,它们在原有的功能基础上,添加了对导出样式的控制,让导出的Excel更加满足业务需要,比如说一些常见的设置字体样式,大小,颜色等待,但是我使用cdn方式引入xlsx-style时没有问题,但是使用ES6 import 语法是出现小问题(网上查询页面解决),在这个过程中,遇见了node-xlsx和js-xlsx,简单使用之后,发现js-xlsx是我要找的,node-xlsx是在js-xlsx的基础之上进行的一层薄薄的封装,不过这层封装也大大降低了js-xlsx的上手难度(值得自己学习),啰里啰嗦低讲到这里你估计又想说了,那就使用被,还费什么话,额~~~废话少说,捡重点的~~~

      先说关于导入日期处理这块,导入的文件中包含三种日期格式,截图如下,关于代码信息,在文章末尾处

    excel截图

    当我看到数据时,我得内心是慌乱的一逼,截图说明下

    js-xlsx将数据直接解析成了个性化数据,浏览过源码就会发现,它是根据excel中的格式进行的格式化,虽然未必能转换成跟office中一模一样,但是确实实现了一大部分,但是这种数据丢给我的程序,我岂不是要凉凉,我们当然是希望他们给我们一种统一的格式(yyyy-MM-dd hh:mm或者时间戳格式),这样才方便自己程序处理,这个问题先记下,

     关于数字的问题,Excel截图如下,我的文件

     

    解析,看数据,截图说明

    哪里有两个问题,价格的值,莫名的多了个空格,而且还是字符串格式,身份证号的值,竟然使用了科学计数法,这,这,好牛B的程序,然而呢。。。我想静静......

    js-xlsx虽然很强大哦,但是他并没有暴露出来一些关于处理数据的入口,哎,思来想去,要不自己改改?

    然后就有了,

    npm上的 songyz-xlsx

    github上的 songyz-xlsx

    另外,相关代码

     1 //表头单元格样式
     2 export const titleStyle = {
     3     font: {
     4         bold: true,
     5     },
     6     alignment: {
     7         horizontal: "center",
     8         vertical: "center",
     9     },
    10     border: {
    11         top: {
    12             style: "thin",
    13         },
    14         bottom: {
    15             style: "thin",
    16         },
    17         left: {
    18             style: "thin",
    19         },
    20         right: {
    21             style: "thin",
    22         },
    23     }
    24 };
    25 //内容单元格样式
    26 export const bodyStyle = {
    27     alignment: {
    28         vertical: "center",
    29     },
    30     border: {
    31         top: {
    32             style: "thin",
    33         },
    34         bottom: {
    35             style: "thin",
    36         },
    37         left: {
    38             style: "thin",
    39         },
    40         right: {
    41             style: "thin",
    42         },
    43     }
    44 };
    xlsx-support/common.js
     1 // 将指定的自然数转换为26进制表示。映射关系:[0-25] -> [A-Z]。
     2 export const getCharCol = (n) => {
     3     let s = '',
     4         m = 0
     5     while (n > 0) {
     6         m = n % 26 + 1
     7         s = String.fromCharCode(m + 64) + s
     8         n = (n - m) / 26
     9     }
    10     return s
    11 }
    12 
    13 //将数据写到文件中
    14 export const writeFile = (fname, data, enc) => {
    15     /*global IE_SaveFile, Blob, navigator, saveAs, URL, document, File, chrome */
    16     if (typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
    17     if (typeof Blob !== 'undefined') {
    18         var blob = new Blob([blobify(data)], { type: "application/octet-stream" });
    19         if (typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
    20         if (typeof saveAs !== 'undefined') return saveAs(blob, fname);
    21         if (typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
    22             var url = URL.createObjectURL(blob);
    23             if (typeof chrome === 'object' && typeof(chrome.downloads || {}).download == "function") {
    24                 if (URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
    25                 return chrome.downloads.download({ url: url, filename: fname, saveAs: true });
    26             }
    27             var a = document.createElement("a");
    28             if (a.download != null) {
    29                 a.download = fname;
    30                 a.href = url;
    31                 document.body.appendChild(a);
    32                 a.click();
    33                 document.body.removeChild(a);
    34                 if (URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
    35                 return url;
    36             }
    37         }
    38     }
    39     // $FlowIgnore
    40     if (typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
    41         // $FlowIgnore
    42         var out = File(fname);
    43         out.open("w");
    44         out.encoding = "binary";
    45         if (Array.isArray(payload)) payload = a2s(payload);
    46         out.write(payload);
    47         out.close();
    48         return payload;
    49     } catch (e) { if (!e.message || !e.message.match(/onstruct/)) throw e; }
    50     throw new Error("cannot save file " + fname);
    51 }
    52 
    53 /* normalize data for blob ctor */
    54 function blobify(data) {
    55     if (typeof data === "string") return s2ab(data);
    56     if (Array.isArray(data)) return a2u(data);
    57     return data;
    58 }
    59 
    60 function s2ab(s) {
    61     if (typeof ArrayBuffer === 'undefined') return s2a(s);
    62     var buf = new ArrayBuffer(s.length),
    63         view = new Uint8Array(buf);
    64     for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
    65     return buf;
    66 }
    67 
    68 function a2u(data) {
    69     if (typeof Uint8Array === 'undefined') throw new Error("Unsupported");
    70     return new Uint8Array(data);
    71 }
    xlsx-support/util.js
     1 import XLSX from 'songyz-xlsx'
     2 
     3 import { titleStyle, bodyStyle } from './xlsx-support/common'
     4 import { getCharCol, writeFile } from './xlsx-support/util'
     5 
     6 //导入文件的类型
     7 export const xlsxTypes = ["xlsx", "xlc", "xlm", "xls", "xlt", "xlw", "csv"];
     8 
     9 //导入文件
    10 export const importSlsx = (file, opts) => {
    11     return new Promise(function (resolve, reject) {
    12         const reader = new FileReader()
    13         reader.onload = function (e) {
    14             opts = opts || {};
    15 
    16             opts.type = 'binary';
    17             opts._dateType = opts._dateType || 1; //1,"yyyy-MM-dd hh:mm",2,时间戳
    18             opts._numberType = opts._numberType || 1; //1,不适用科学计数法,2,使用科学计数法
    19 
    20             const wb = XLSX.read(e.target.result, opts);
    21             resolve(Object.keys(wb.Sheets).map(key => XLSX.utils.sheet_to_json(wb.Sheets[key])).reduce((prev, next) => prev.concat(next)))
    22         }
    23         reader.readAsBinaryString(file.raw)
    24     })
    25 }
    26 
    27 //导出数据
    28 export const exportXlsx = (dataArray, fileName) => {
    29     let type = 'xlsx';
    30     dataArray = dataArray || [{}];
    31     fileName = fileName || 'file';
    32 
    33     var keyMap = Object.keys(dataArray[0]);
    34     var title = {};
    35     keyMap.forEach(key => title[key] = key);
    36     dataArray.unshift(title);
    37 
    38     //用来保存转换好的json 
    39     var sheetData = [];
    40 
    41     dataArray.map((row, i) => {
    42         let style = i == 0 ? titleStyle : bodyStyle;
    43         return keyMap.map((key, j) => {
    44             return {
    45                 style: style,
    46                 value: row[key],
    47                 position: (j > 25 ? getCharCol(j) : String.fromCharCode(65 + j)) + (i + 1)
    48             };
    49         })
    50     }).reduce((prev, next) => prev.concat(next)).forEach((cell, i) =>
    51         sheetData[cell.position] = {
    52             v: cell.value,
    53             s: cell.style
    54         }
    55     );
    56     var outputPos = Object.keys(sheetData); //设置区域,比如表格从A1到D10
    57 
    58     var wb = {
    59         SheetNames: ['mySheet'], //保存的表标题
    60         Sheets: {
    61             'mySheet': Object.assign({},
    62                 sheetData, //内容
    63                 {
    64                     '!ref': outputPos[0] + ':' + outputPos[outputPos.length - 1] //设置填充区域
    65                 }
    66             )
    67         }
    68     };
    69     var buffer = XLSX.write(wb, { bookType: type, bookSST: false, type: 'buffer' });
    70 
    71     writeFile(fileName + "." + type, buffer);
    72 }
    xlsx-util.js

     欢迎大家在评论区指正,不吝赐教!!!

  • 相关阅读:
    玩懂Log,打开Android大门(sundy深入浅出)之一
    ListView 中getView的原理+如何在ListView中放置多个item(android.widget.ListView)
    验证视图状态MAC失败问题正确的解决办法
    Coolite Extjs Store开发心得(转)
    Delphi进制转换
    得到Exitjs DataView中图片文件名
    C#文件常用操作
    Delphi中TList类应用
    代码优化的第一步是判定程序热点(转)
    Asp.net性能优化
  • 原文地址:https://www.cnblogs.com/songyz/p/songyz-xlsx.html
Copyright © 2020-2023  润新知