今天整理出在Web前端導出Excel的寫法,寫了一個工具類,對各個瀏覽器進行了兼容。
首先,導出的數據來源可能有兩種:
1. 頁面的HTML內容(一般是table)
2. 純數據
PS:不同的數據源,導出的寫法也是不相同的。
技術方案
IE
無論數據來源是哪里,都是用ActiveXObject對象及相關的命令,IE10、11有點不同。
非IE
純數據的,使用一個FileSaver.js,如果有瀏覽器不支持Blob的,還需要引入Blob.js,來做導出。
HTML內容的,構造一個base64字符串的路徑,跳轉地址下載,其實也可以將數據抽出來,用純數據的方式。
PS:自行了解Blob對象。
關鍵問題
1. 非IE導出純數據中文亂碼
解決方法:在Blob的數據要加上"\uFEFF"做修正。
2. Safari的Blob報TypeError: '[object BlobConstructor]' is not a constructor
原因:應該Safari的Blob是不完整的。
解決方法:需要引入一個Blob.js做修正,不過下載的文件會顯示"UnKnown",但加上后綴名xls,文件內容還是可以看的(暫時沒有很好辦法)。
3. Blob每個值是以逗號分隔,那數據有逗號怎么辦
解決方法:需要在每個值額外裹上雙引號,這樣不會影響導出結果,導出內容也是正確的。
4. 非IE導出HTML內容(非table),樣式丟失
解決方法:額,這個沒有辦法,可以將數據抽出來,用純數據的方式導出。
代碼實現
(function(){ var EXCEL_CONTENTTYPE = "application/vnd.ms-excel;", EXCEL_URI = 'data:application/vnd.ms-excel;base64,', EXCE_TEMPLATE = '<html><head><meta charset="UTF-8"></head><body>{html}</body></html>', __PREVFIX = "\uFEFF", ieVersion = window.navigator.userAgent.toLowerCase().match(/(msie\s|trident.*rv:)([\w.]+)/), useIE = ieVersion && ieVersion[2] < 10, isIE1011 = ieVersion && ieVersion[2] > 9; var Export = { /* *@param datas Two-dimensional array : datas, export only with data or String : DOM id, export html content *@param fileName export file name */ toExcel: function(datas, fName){ var isId = typeof datas === 'string'; if(isId || datas instanceof Array){ if(useIE || isId && isIE1011){ Export.__ieExport(datas); } else{ Export.__oTherExport(datas, fName); } } else{ alert("datas params need Two-dimensional array or String."); } }, __ieExport : function(datas){ var oXL = new ActiveXObject("Excel.Application"), oWB = oXL.Workbooks.Add(), oSheet = oWB.ActiveSheet, i = 0, j; if(typeof datas === 'string'){ var elem = document.getElementById(datas); var sel = document.body.createTextRange(); sel.moveToElementText(elem); try{ sel.select();
//there ie10、11 will be error, i don't know why, but also can export } catch(e){} sel.execCommand("Copy"); oSheet.Paste(); } else { for(; i < datas.length; i++){ var row = datas[i]; for (j = 0; j < row.length; j++) { oSheet.Cells(i + 1, j + 1).value = row[j]; } } } oXL.Visible = true; }, __oTherExport : function(datas, fileName){ if(typeof datas === 'string'){ var elem = document.getElementById(datas), content = EXCE_TEMPLATE.replace("{html}", elem.outerHTML); //TODO: need test large amount of data window.location.href = EXCEL_URI +
window.btoa(unescape(encodeURIComponent(content))); } else { var blob, i = 0, j, str = __PREVFIX; for(; i < datas.length; i++){ var row = datas[i]; // the value add double quotation marks on both sides, for separate values. str += "\""+ row.join("\",\"") + "\"\n"; } //on safari: TypeError: '[object BlobConstructor]' is not a constructor (evaluating 'new Blob([str],{ //import Blob.js to fix, but still have a problem : the fileName will be 'Unknown' ,
//but if you add suffix name, content can be seen. blob = new Blob([str],{ type: EXCEL_CONTENTTYPE }); saveAs(blob, fileName || "Download.xls"); } } } window.ExportUtil = Export; })();
演示示例:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>demo</title> <style type="text/css"> ul{ list-style:none; padding:0px; margin:0px; width:590px; height:20px; line-height:20px; border:1px solid #99CC00; border-top:0px; font-size:12px;} ul li{ display:block; width:33%; float:left;text-indent:2em} .th{ background:#F1FADE; font-weight:bold; border-top:1px } </style> </head> <body> <div> <table id="tb" border=4 width=250 align=center> <caption>【表格舉例】</caption> <tr bgcolor="#cccccc"> <th><br></th> <th>列-A</th> <th>列-B</th> <th>列-C</th> </tr> <tr align=center> <td>行-1</td> <td>A1</td> <td>B1</td> <td rowspan=2>C1-C2</td> </tr> <tr align=center> <td>行-2</td> <td>A2</td> <td>B2</td> </tr> <tr align=center> <td>行-3</td> <td>A3</td> <td colspan=2>A3-B3</td> </tr> </table> <div id="tul"> <h1><a href="http://www.66css.com">www.66css.com</a></h1> <ul class="th"> <li>姓名</li> <li>班級</li> <li>年齡</li> </ul> <ul> <li>阿三</li> <li>3-1</li> <li>13</li> </ul> <ul> <li>小龍</li> <li>2-4</li> <li>16</li> </ul> <ul> <li>大馬</li> <li>5-3</li> <li>17</li> </ul> </div> <script src="Blob.js"></script> <script src="FileSaver.min.js"></script> <script src="ExportUtil.js"></script><!--工具類--> <script> //demo 1 ExportUtil.toExcel([ ["學號", "姓名", "年齡"], ["001", "張學友", "40"], ["002", "張信哲", "38"], ["003", "林志炫", "41"], ["004", "劉亦菲", "24"], ["005", "賈玲", "30"], ["006", "陳一發", "23"] ],"hello.xls"); //demo2 ExportUtil.toExcel("tb"); //demo3 ExportUtil.toExcel("tul"); //ie的有樣式,但某些樣式會丟失。 </script> </body> </html>
代碼下載
我將完整代碼放這:https://github.com/codingforme/code-learn/tree/master/export-excel
總結
這個導出Excel工具類兼容了Chrome、Firefox、Safari(不完美)、IE6-11,針對兩種數據源都做了處理。一般來說,純數據導出的效果是最好的,所以如果HTML內容導出方式不滿意,可以將數據抽出,用回純數據導出。最后,這個工具缺失的是對大數據量導出的測試,不過這個后面有空再進行驗證。
本文為原創文章,轉載請保留原出處,方便溯源,如有錯誤地方,謝謝指正。