js文件操作之——导出Excel (js-xlsx)
Posted youryida
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js文件操作之——导出Excel (js-xlsx)相关的知识,希望对你有一定的参考价值。
前阵子跟server同学讨论一个Excel导出的需求,我说JS搞不定,需要server来做,被server同学强行打脸。
今天研究了下,尼玛,不光可以,还很强大了!
总结:经验是害人的,尤其是在发展迅速的前端圈儿,and,需要保持饥渴,保持对新技术的敏感度。
注:以下只探讨现代浏览器
1. 最简单的Excel导出
原理:js可以通过base64或者blob,把一个包含一个<table>的<html>串,导出成xx.xls格式。而Excel可以打开html文件。这样看起来,就是一个成功的Excel导出。
var tableHtml=‘<html><head><meta charset="UTF-8"></head><body><table><tr><td>only one</td></tr></table></body></html>‘; //base64 URL形式文件下载 var oa = document.createElement(‘a‘); oa.href = ‘data:application/vnd.ms-excel;base64,‘+window.btoa(tableHtml); oa.download = ‘htmltable-base64.xls‘;//通过A标签 设置文件名 oa.click();
文件,在js中,除了可以是base64,也可以是一个blob。
- base64形式的文件描述,在js或者html中,就是一个很长的base4字符串
- blob形式的文件描述,在js或者html中,是一个URL形式的字符串,他指向的是浏览器内存中的一个文件片段,形如"blob:http://sheetjs.com/f999f57f-b79f-4293-a317-3bbf6ea58788"
blob形式的Excel导出,如下:
//blob URL形式文件下载 var tableHtml=‘<html><head><meta charset="UTF-8"></head><body><table><tr><td>only one</td></tr></table></body></html>‘; var excelBlob = new Blob([tableHtml], {type: ‘application/vnd.ms-excel‘}); var oa = document.createElement(‘a‘); oa.href = URL.createObjectURL(excelBlob); oa.download = ‘htmltable-blob.xls‘; document.body.appendChild(oa); oa.click();
毛病:
- 这是个假的excel文件,只有xls格式可以在Excel中打开,xlsx不行。
2. 真正的Excel导出
是的,这里有一个真正的二进制Excel文件导出。
他就是一万多star的js-xlsx,地址:https://github.com/SheetJS/js-xlsx
我花了两个多小时,追了好一阵子他的https://github.com/SheetJS/js-xlsx/blob/master/xlsx.js,终于,我搞明白他是什么原理了。
以下拿他的官方demo举例,http://sheetjs.com/demos/table.html。
从网页的table DOM到Excel文件的演化过程如下:
2.1 网页上的table
This | is | a | Test |
??????? | ?????? | 你好 | ??? |
1 | 2 | 3 | 4 |
Click | to | edit | cells |
2.2 sheet JSON
这里,他用一个json来描述了Excel表格中的A1,B1,C1等各个单元格。
{"Sheet JS":{"A1":{"t":"s","v":"This"},"B1":{"t":"s","v":"is"},"C1":{"t":"s","v":"a"},"D1":{"t":"s","v":"Test"},"A2":{"t":"s","v":"???????"},"B2":{"t":"s","v":"??????"},"C2":{"t":"s","v":"你好"},"D2":{"t":"s","v":"???"},"A3":{"t":"n","v":1},"B3":{"t":"n","v":2},"C3":{"t":"n","v":3},"D3":{"t":"n","v":4},"A4":{"t":"s","v":"Click"},"B4":{"t":"s","v":"to"},"C4":{"t":"s","v":"edit"},"D4":{"t":"s","v":"cells"},"!ref":"A1:D4"}}
2.3 未压缩的zip文件
源码中的“write_zip_type”方法,它按照标准的电子表格格式协议,把上述JSON转成了下面的样子。
如下,很明显,这里面包含了一些乱码和一些xml描述。
(这里本着不求甚解的精神,我咨询了一下我们部门的资深技术专家,他搭眼一看,说这是一个未压缩的zip。我也懒得输出一下zip来验证这个了,他说是,那就是了)
PK Ã?æLÖ?|ZZdocProps/core.xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>PK Ã?æLþù«44docProps/app.xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Application>SheetJS</Application><HeadingPairs><vt:vector size="2" baseType="variant"><vt:variant><vt:lpstr>Worksheets</vt:lpstr></vt:variant><vt:variant><vt:i4>1</vt:i4></vt:variant></vt:vector></HeadingPairs><TitlesOfParts><vt:vector size="1" baseType="lpstr"><vt:lpstr>Sheet JS</vt:lpstr></vt:vector></TitlesOfParts></Properties>PK Ã?æLT?Ä8ããxl/worksheets/sheet1.xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><dimension ref="A1:D4"/><sheetViews><sheetView workbookViewId="0"/></sheetViews><sheetData><row r="1"><c r="A1" t="str"><v>This</v></c><c r="B1" t="str"><v>is</v></c><c r="C1" t="str"><v>a</v></c><c r="D1" t="str"><v>Test</v></c></row><row r="2"><c r="A2" t="str"><v>வணà®?à¯?à®?à®®à¯?</v></c><c r="B2" t="str"><v>สวัสà¸?ี</v></c><c r="C2" t="str"><v>ä½ å¥½</v></c><c r="D2" t="str"><v>ê°?ì§?ë§?</v></c></row><row r="3"><c r="A3"><v>1</v></c><c r="B3"><v>2</v></c><c r="C3"><v>3</v></c><c r="D3"><v>4</v></c></row><row r="4"><c r="A4" t="str"><v>Click</v></c><c r="B4" t="str"><v>to</v></c><c r="C4" t="str"><v>edit</v></c><c r="D4" t="str"><v>cells</v></c></row></sheetData><ignoredErrors><ignoredError numberStoredAsText="1" sqref="A1:D4"/></ignoredErrors></worksheet>PK Ã?æLÜè¯ÏDDxl/workbook.xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><workbookPr codeName="ThisWorkbook"/><sheets><sheet name="Sheet JS" sheetId="1" r:id="rId1"/></sheets></workbook>PK Ã?æL0?kÞÞxl/theme/theme1.xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme"><a:themeElements><a:clrScheme name="Office"><a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1><a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1><a:dk2><a:srgbClr val="1F497D"/></a:dk2><a:lt2><a:srgbClr val="EEECE1"/></a:lt2><a:accent1><a:srgbClr val="4F81BD"/></a:accent1><a:accent2><a:srgbClr val="C0504D"/></a:accent2><a:accent3><a:srgbClr val="9BBB59"/></a:accent3><a:accent4><a:srgbClr val="8064A2"/></a:accent4><a:accent5><a:srgbClr val="4BACC6"/></a:accent5><a:accent6><a:srgbClr val="F79646"/></a:accent6><a:hlink><a:srgbClr val="0000FF"/></a:hlink><a:folHlink><a:srgbClr val="800080"/></a:folHlink></a:clrScheme><a:fontScheme name="Office"><a:majorFont><a:latin typeface="Cambria"/><a:ea typeface=""/><a:cs typeface=""/><a:font script="Jpan" typeface="ï¼ï¼³ ï¼°ã?´ã?·ã??ã?¯"/><a:font script="Hang" typeface="ë§?ì?? ê³ ë??"/><a:font script="Hans" typeface="å®?ä½?"/><a:font script="Hant" typeface="æ?°ç´°æ??é«?"/><a:font script="Arab" typeface="Times New Roman"/><a:font script="Hebr" typeface="Times New Roman"/><a:font script="Thai" typeface="Tahoma"/><a:font script="Ethi" typeface="Nyala"/><a:font script="Beng" typeface="Vrinda"/><a:font script="Gujr" typeface="Shruti"/><a:font script="Khmr" typeface="MoolBoran"/><a:font script="Knda" typeface="Tunga"/><a:font script="Guru" typeface="Raavi"/><a:font script="Cans" typeface="Euphemia"/><a:font script="Cher" typeface="Plantagenet Cherokee"/><a:font script="Yiii" typeface="Microsoft Yi Baiti"/><a:font script="Tibt" typeface="Microsoft Himalaya"/><a:font script="Thaa" typeface="MV Boli"/><a:font script="Deva" typeface="Mangal"/><a:font script="Telu" typeface="Gautami"/><a:font script="Taml" typeface="Latha"/><a:font script="Syrc" typeface="Estrangelo Edessa"/><a:font script="Orya" typeface="Kalinga"/><a:font script="Mlym" typeface="Kartika"/><a:font script="Laoo" typeface="DokChampa"/><a:font script="Sinh" typeface="Iskoola Pota"/><a:font script="Mong" typeface="Mongolian Baiti"/><a:font script="Viet" typeface="Times New Roman"/><a:font script="Uigh" typeface="Microsoft Uighur"/><a:font script="Geor" typeface="Sylfaen"/></a:majorFont><a:minorFont><a:latin typeface="Calibri"/><a:ea typeface=""/><a:cs typeface=""/><a:font script="Jpan" typeface="ï¼ï¼³ ï¼°ã?´ã?·ã??ã?¯"/><a:font script="Hang" typeface="ë§?ì?? ê³ ë??"/><a:font script="Hans" typeface="å®?ä½?"/><a:font script="Hant" typeface="æ?°ç´°æ??é«?"/><a:font script="Arab" typeface="Arial"/><a:font script="Hebr" typeface="Arial"/><a:font script="Thai" typeface="Tahoma"/><a:font script="Ethi" typeface="Nyala"/><a:font script="Beng" typeface="Vrinda"/><a:font script="Gujr" typeface="Shruti"/><a:font script="Khmr" typeface="DaunPenh"/><a:font script="Knda" typeface="Tunga"/><a:font script="Guru" typeface="Raavi"/><a:font script="Cans" typeface="Euphemia"/><a:font script="Cher" typeface="Plantagenet Cherokee"/><a:font script="Yiii" typeface="Microsoft Yi Baiti"/><a:font script="Tibt" typeface="Microsoft Himalaya"/><a:font script="Thaa" typeface="MV Boli"/><a:font script="Deva" typeface="Mangal"/><a:font script="Telu" typeface="Gautami"/><a:font script="Taml" typeface="Latha"/><a:font script="Syrc" typeface="Estrangelo Edessa"/><a:font script="Orya" typeface="Kalinga"/><a:font script="Mlym" typeface="Kartika"/><a:font script="Laoo" typeface="DokChampa"/><a:font script="Sinh" typeface="Iskoola Pota"/><a:font script="Mong" typeface="Mongolian Baiti"/><a:font script="Viet" typeface="Arial"/><a:font script="Uigh" typeface="Microsoft Uighur"/><a:font script="Geor" typeface="Sylfaen"/></a:minorFont></a:fontScheme><a:fmtScheme name="Office"><a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs><a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="16200000" scaled="1"/></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="100000"/><a:shade val="100000"/><a:satMod val="130000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="50000"/><a:shade val="100000"/><a:satMod val="350000"/></a:schemeClr></a:gs></a:gsLst><a:lin ang="16200000" scaled="0"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w="9525" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"><a:shade val="95000"/><a:satMod val="105000"/></a:schemeClr></a:solidFill><a:prstDash val="solid"/></a:ln><a:ln w="25400" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln><a:ln w="38100" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="38000"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr></a:outerShdw></a:effectLst><a:scene3d><a:camera prst="orthographicFront"><a:rot lat="0" lon="0" rev="0"/></a:camera><a:lightRig rig="threePt" dir="t"><a:rot lat="0" lon="0" rev="1200000"/></a:lightRig></a:scene3d><a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs><a:gs pos="40000"><a:schemeClr val="phClr"><a:tint val="45000"/><a:shade val="99000"/><a:satMod val="350000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs></a:gsLst><a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs></a:gsLst><a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults><a:spDef><a:spPr/><a:bodyPr/><a:lstStyle/><a:style><a:lnRef idx="1"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="3"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="2"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="lt1"/></a:fontRef></a:style></a:spDef><a:lnDef><a:spPr/><a:bodyPr/><a:lstStyle/><a:style><a:lnRef idx="2"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="0"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="1"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="tx1"/></a:fontRef></a:style></a:lnDef></a:objectDefaults><a:extraClrSchemeLst/></a:theme>PK Ã?æLUô?ZZ xl/styles.xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><numFmts count="1"><numFmt numFmtId="56" formatCode=""ä¸?å??/ä¸?å?? "hh"æ??"mm"å??"ss"ç§? ""/></numFmts><fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts><fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills><borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/></cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles><dxfs count="0"/><tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/></styleSheet>PK Ã?æL÷Â?00[Content_Types].xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Default Extension="xml" ContentType="application/xml"/><Default Extension="bin" ContentType="application/vnd.ms-excel.sheet.binary.macroEnabled.main"/><Default Extension="vml" ContentType="application/vnd.openxmlformats-officedocument.vmlDrawing"/><Default Extension="bmp" ContentType="image/bmp"/><Default Extension="png" ContentType="image/png"/><Default Extension="gif" ContentType="image/gif"/><Default Extension="emf" ContentType="image/x-emf"/><Default Extension="wmf" ContentType="image/x-wmf"/><Default Extension="jpg" ContentType="image/jpeg"/><Default Extension="jpeg" ContentType="image/jpeg"/><Default Extension="tif" ContentType="image/tiff"/><Default Extension="tiff" ContentType="image/tiff"/><Default Extension="pdf" ContentType="application/pdf"/><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>PK Ã?æLJjùLL_rels/.rels<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>PK Ã?æLÐ?dÝ--xl/_rels/workbook.xml.rels<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/></Relationships>PK Ã?æLÖ?|ZZdocProps/core.xmlPK Ã?æLþù«44?docProps/app.xmlPK Ã?æLT?Ä8ããëxl/worksheets/sheet1.xmlPK Ã?æLÜè¯ÏDDxl/workbook.xmlPK Ã?æL0?kÞÞu xl/theme/theme1.xmlPK Ã?æLUô?ZZ ?‘xl/styles.xmlPK Ã?æL÷Â?00 ,[Content_Types].xmlPK Ã?æLJjùLLj3_rels/.relsPK Ã?æLÐ?dÝ--ß5xl/_rels/workbook.xml.relsPK >D8
2.4 Blob URL
其实,我最感兴趣的是这儿。2.3中的一大坨字符串,通过 Uine8Array转成了无符号数组,并通过new Blob方法,转成了二进制文件片段,关键代码如下:
function blobify(strData) { var buf = new ArrayBuffer(strData.length), view = new Uint8Array(buf); for (var i=0; i!=strData.length; ++i) view[i] = strData.charCodeAt(i) & 0xFF; return buf; } var excelBlob = new Blob([blobify(data)], {type:"application/octet-stream"}); var blobURL=URL.createObjectURL(excelBlob);
最后,通过URL.createObjectURL方法,把blob转成了,肉眼可见的js和HTML中可以看到的,Blob URL,如下:
blob:http://sheetjs.com/f999f57f-b79f-4293-a317-3bbf6ea58788
尼玛,一个html转Excel的库js,有20170行代码,恩,不错,开源万岁。
3. 总结
看起来,先不说性能如何,上面这些关键API利用一下,js应该是可以导出很多种格式的文件了。
- 文本类的,txt html js css xml
- 特定协议的文档,pdf Excel cvs(看起来word ppt 应该也可以了,懒得去查了)
- 其他各类二进制文件,zip png jpg gif (不晓得是不是可以导出音视频...)
以上是关于js文件操作之——导出Excel (js-xlsx)的主要内容,如果未能解决你的问题,请参考以下文章