關於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

 

 歡迎大家在評論區指正,不吝賜教!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM