csv与xlsx导出
一.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占用的内存
三.前端导出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来做类型的限定,保证类型的确定性以及减少前端相应工作量;
四. 总结
csv文件格式简单,在前端实现上相对简单,无需引入额外的库文件,对于一般的表格导出均可满足需求;xlsx文件格式复杂,需要引用第三方库文件进行处理,其可以文件预览、类型限定、SQL查询、内容包含图表、一个工作簿中包含多个表等,使用场景更大。