一.csv与xlsx格式基本介绍 
 
      csv即comma seperate values - 逗号分隔值,文件以纯文本形式来存储表格数据,它可以由任意数目的记录组成,记录之间通过某种换行符来分隔如 ’\r\n’,而每条记录由字段组成,字段之间的分隔符一般通过逗号来分隔即  ’,’,因此csv是一种比较简单的文件格式,在编辑器中打开如下所示 
 
      xlsx是Microsoft Excel 2007之后的扩展名,其本身是一种新的基于XML的压缩文件,相对于传统的xls文件占用空间更小,在后缀名之后添加.zip即可解压缩,如下所示: 
 
 
 二. 前端导出csv格式文件 
 
       csv格式 - csv格式本身比较简单,所以前端只需要对数据按照格式(记录之间通过换行符分隔,记录中的字段之间通过逗号分隔)进行处理即可,一般不需要引入额外的库,基本的使用方法如下: 
 
   <!DOCTYPE html> 
 
 
 
   <html lang="en"> 
 
 
 
   <head> 
 
 
 
     <meta charset="UTF-8"> 
 
 
 
     <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
 
 
 
     <meta http-equiv="X-UA-Compatible" content="ie=edge"> 
 
 
 
     <title>Document</title> 
 
 
 
   </head> 
 
 
 
   <body> 
 
 
 
   <button id="btn">下载</button> 
 
 
 
   <a id="downloadCsv"></a> 
 
 
 
   <script> 
 
 
 
   const btn = document.getElementById('btn'); 
 
 
 
   btn.addEventListener('click', function () { 
 
 
 
     let headers = ['时段', '2018-08-01', '2018-08-01', '2018-08-01']; 
 
 
 
     let dataSource = [ 
 
 
 
       ['00时', 345, 65, 8], 
 
 
 
       ['06时', 23, 56, 89], 
 
 
 
       ['12时', 21, 4, 7], 
 
 
 
       ['18时', 67, 9, 34], 
 
 
 
     ]; 
 
 
 
     let csv = '\uFEFF'; 
 
 
 
     csv += headers.join(',') + '\r\n'; 
 
 
 
     dataSource.forEach( (record) => { 
 
 
 
       csv += (record.join(',') + '\r\n'); 
 
 
 
     }); 
 
 
 
     const blob = new window.Blob([csv], { type: 'text/csv,charset=UTF-8' }); 
 
 
 
     const downloadCsv = document.getElementById('downloadCsv'); 
 
 
 
     downloadCsv.href = window.URL.createObjectURL(blob); 
 
 
 
     downloadCsv.click(); 
 
 
 
     window.URL.revokeObjectURL(blob); 
 
 
 
   }) 
 
 
 
   </script> 
 
 
 
   </body> 
 
 
 
   </html> 
 
 
  值得注意的有以下几点: 
 
- 在csv文件的开头需要添加BOM,这里使用\uFEFF表示此文件使用UTF-16进行编码
 - 在创建Blob时,第一个参数必须是数组
 - 在下载完成最后,需要及时清除Blob占用的内存
 
  可以在 
 https://jsfiddle.net/veh7asqk/1/查看效果 
 
 
 三.前端导出excel格式文件 
 
      excel格式文件比较复杂,在实现上一般可以引用第三方库 
 https://github.com/sheetjs/js-xlsx,它可以简化xlsx文件的各种操作:读取、预览、web sql查询、编辑、导出,可以访问 
 https://sheetjs.com/opensource查看更多;这里主要陈述如何导出xlsx类型的文件 
 
      打开一个excel表,可以发现其主要的格式如下: 
 
        A     B      C     D      E 
 
  1    A1   B1    C1   D1    E1 
 
  2    A2   B2    C2   D2    E2 
 
  3    A3   B3    C3   D3    E3 
 
  4    A4   B4    C4   D4    E4 
 
      所以前端对于数据的处理过程就是将数据按照上面的格式进行匹配,一个简单的例子如下所示: 
 
   <!DOCTYPE html> 
 
 
 
   <html lang="en"> 
 
 
 
   <head> 
 
 
 
     <meta charset="UTF-8"> 
 
 
 
     <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
 
 
 
     <meta http-equiv="X-UA-Compatible" content="ie=edge"> 
 
 
 
     <title>Document</title> 
 
 
 
     <!-- XLSX --> 
 
 
 
     <script src=" 
  https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script> 
 
 
 
     <!-- fileSaver saveAs --> 
 
 
 
     <script src=" 
  https://cdn.rawgit.com/eligrey/FileSaver.js/e9d941381475b5df8b7d7691013401e171014e89/FileSaver.min.js"></script> 
 
 
 
   </head> 
 
 
 
   <body> 
 
 
 
     <button id="btn"/>下载</button> 
 
 
 
     <script> 
 
 
 
     function createWorkSheet (XLSX, tableCols, tableData) { 
 
 
 
       var EMPTY_XSLX_BASE64 = ''; 
 
 
 
       var workbook = XLSX.read(EMPTY_XSLX_BASE64, { type: 'base64' }); 
 
 
 
       var sheets = { 
 
 
 
       Sheet1: {}, 
 
 
 
       }; 
 
 
 
       var sheetNames = ['Sheet1']; 
 
 
 
       var idx = 0; 
 
 
 
       var colNum = tableCols.length; 
 
 
 
       var rowNum = tableData.length; 
 
 
 
       // 输入表头 
 
 
 
       for (idx = 0; idx < colNum; idx++) { 
 
 
 
         var title = tableCols[idx]; 
 
 
 
         sheets.Sheet1[String.fromCharCode(65 + idx) + '1'] = { 
 
 
 
           t: 's', 
 
 
 
           v: title.name, 
 
 
 
         }; 
 
 
 
       } 
 
 
 
       // 插入每行的数据值 
 
 
 
       for (let n = 0; n < rowNum; n++) { 
 
 
 
         let key = tableCols[0].key; 
 
 
 
         let v = tableData[n][key] + ''; 
 
 
 
         sheets.Sheet1[String.fromCharCode(65) + (n + 2)] = { 
 
 
 
           t: 'n', 
 
 
 
           v: v, 
 
 
 
         }; 
 
 
 
       } 
 
 
 
       for (let n = 0; n < rowNum; n++) { 
 
 
 
         let key = tableCols[1].key; 
 
 
 
         let v = tableData[n][key] + ''; 
 
 
 
         sheets.Sheet1[String.fromCharCode(65 + 1) + (n + 2)] = { 
 
 
 
           t: 's 
  ’ 
  ,   
 
 
 
           v: v, 
 
 
 
         } 
 
 
 
       } 
 
 
 
       for (let n = 0; n < rowNum; n++) { 
 
 
 
         for (idx = 2; idx < colNum; idx++) { 
 
 
 
           let key = tableCols[idx].key; 
 
 
 
           let v = tableData[n][key]; 
 
 
 
             sheets.Sheet1[String.fromCharCode(65 + idx) + (n + 2)] = { 
 
 
 
               t: 'n', 
 
 
 
               v: v, 
 
 
 
           }; 
 
 
 
         } 
 
 
 
       } 
 
 
 
       sheets.Sheet1['!ref'] = 'A1:' + String.fromCharCode(65 + colNum - 1) + (rowNum + 1); 
 
 
 
       workbook.Sheets = sheets; 
 
 
 
       workbook.SheetNames = sheetNames; 
 
 
 
       return workbook; 
 
 
 
     } 
 
 
 
     function a2ab (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; 
 
 
 
     } 
 
 
 
     const headers = [ 
 
 
 
       { 
 
 
 
         name: '序号', 
 
 
 
         key: 'No', 
 
 
 
       }, 
 
 
 
       { 
 
 
 
         name: '应用名称', 
 
 
 
         key: 'AppName', 
 
 
 
       }, 
 
 
 
       { 
 
 
 
         name: '日活跃用户数(万)', 
 
 
 
         key: 'DAU', 
 
 
 
       }, 
 
 
 
       { 
 
 
 
         name: '月数(万)', 
 
 
 
         key: 'MAU', 
 
 
 
       } 
 
 
 
     ]; 
 
 
 
     const dataSource = [ 
 
 
 
       { 
 
 
 
         No: 1, 
 
 
 
         AppName:   
  ‘a', 
 
 
 
         DAU: 17900, 
 
 
 
         MAU: 50000, 
 
 
 
       }, 
 
 
 
       { 
 
 
 
         No: 2, 
 
 
 
         AppName:   
  ‘b', 
 
 
 
         DAU: 12500, 
 
 
 
         MAU: 40000, 
 
 
 
       }, 
 
 
 
       { 
 
 
 
         No: 3, 
 
 
 
         AppName:   
  ‘c', 
 
 
 
         DAU: 4400, 
 
 
 
         MAU: 15000, 
 
 
 
       }, 
 
 
 
       { 
 
 
 
         No: 4, 
 
 
 
         AppName:   
  ‘d', 
 
 
 
         DAU: 4800, 
 
 
 
         MAU: 17000, 
 
 
 
       }, 
 
 
 
     ]; 
 
 
 
     function download (fileName) { 
 
 
 
       let wb = createWorkSheet(XLSX, headers, dataSource); 
 
 
 
       let wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: true, type: 'binary'}); 
 
 
 
       saveAs(new Blob([a2ab(wbout)], {type: 'application/octet-stream'}), fileName); 
 
 
 
     } 
 
 
 
     let btn = document.getElementById('btn'); 
 
 
 
     btn.addEventListener('click', function () { 
 
 
 
     const fileName = 'example.xlsx'; 
 
 
 
       download(fileName); 
 
 
 
     }) 
 
 
 
   </script> 
 
 
 
   </body> 
 
 
 
   </html> 
 
 
  这里导出的是一个工作簿,工作簿中包含多个表,所以通过这种方式可以输出多个表从而方便用户查看;另外,在格式化过程中可以针对导出表格式需要来规定每个字段的type来做类型的限定,保证类型的确定性以及减少前端相应工作量; 
 
  可以在 
 https://jsfiddle.net/q8dgvL3w/2/查看效果 
 
 
 四. 总结  
 
      csv文件格式简单,在前端实现上相对简单,无需引入额外的库文件,对于一般的表格导出均可满足需求;xlsx文件格式复杂,需要引用第三方库文件进行处理,其可以文件预览、类型限定、SQL查询、内容包含图表、一个工作簿中包含多个表等,使用场景更大。 
 
