ExcelJS用于读写各种电子表格,
官方说明文档:https://github.com/exceljs/exceljs/blob/master/README_zh.md
导出
项目采用异步提交后返回json数组,回调处理生成并下载Excel,其中sdata为导出字段信息,包括字段名称、字段描述、是否合并,合并是指一列中相邻单元格内容一样;
//输入两个json数组,导出表格,2020-05-12
function exportByExcelJs(json, sdata) {
//init
var workbook = new ExcelJS.Workbook();
workbook.creator = 'ExcelJS';
workbook.created = new Date();
workbook.modified = new Date();
var worksheet = workbook.addWorksheet('Sheet1');
//行集
var rows = [];
//单行
var rowValues = [];
//标题行空白
sdata.forEach(function(o) {
rowValues.push('');
});
rows.push(rowValues);
//表头行
rowValues = [];
sdata.forEach(function(o) {
rowValues.push(o.text);
});
rows.push(rowValues);
//数据行
json.forEach(function(o) {
rowValues = [];
sdata.forEach(function(ele) {
//日期格式转换,2020-04-12
if (/Date\((-?\d+)\)/.test(o[ele.field])) {
o[ele.field] = getFDate(o[ele.field]);
}
rowValues.push(o[ele.field]);
});
rows.push(rowValues);
});
//加入表单
worksheet.addRows(rows);
//表头行加注释
for (var i in sdata) {
var cellName = getColumnNameByIndex(i) + '2';
worksheet.getCell(cellName).note = sdata[i].field;
};
//默认单元格样式
var style = {
font: {
name: '宋体',
size: 11,
bold: false,
//color: { argb: 'FFFF0000' }
},
alignment: {
vertical: 'middle',
horizontal: 'center',
wrapText: false
},
border: {
top: {
style: "thin",
},
bottom: {
style: "thin",
},
left: {
style: "thin",
},
right: {
style: "thin",
},
},
}
//设置单元格样式,设置列或行属性有问题,且会造成所有行列生效,2020-05-13
for (var i = 1; i < worksheet._columns.length + 1; i++) {
worksheet.getColumn(i).width = 15; //列宽
for (var k = 1; k < worksheet._rows.length + 1; k++) {
worksheet.getRow(k).height = 13.5; //行高
var cellName = getColumnNameByIndex(i - 1) + k;
//console.log(cellName);
worksheet.getCell(cellName).style = style;
}
};
//合并单元格,2020-05-13
for (var i = 0; i < worksheet._columns.length; i++) {
if (sdata[i].merge) {
MergeColumn(worksheet, 3, i, worksheet._rows.length);
}
}
//console.log(worksheet);
workbook.xlsx.writeBuffer().then(function(buffer) {
saveAs(new Blob([buffer], {
type: 'application/octet-stream'
}), "成绩分析" + getFullTime() + ".xlsx");
});
}
合并单元格
//合并单元格,2020-05-06
function MergeColumn(sheet, StartRowNum, ColumnIndex, LastRowNum) {
var rowNum = 0; //初始化为数字,便于计算
for (var i = StartRowNum; i < LastRowNum + 1; i++) {
var startCellName = getColumnNameByIndex(ColumnIndex) + i;
var startValue = sheet.getCell(startCellName).value;
for (var k = i + 1; k < LastRowNum + 1; k++) {
var currCellName = getColumnNameByIndex(ColumnIndex) + k;
var currValue = sheet.getCell(currCellName).value;
if (startValue != currValue) {
if (k != i + 1) {
//合并到前一个单元格
rowNum = k - 1;
var preCellName = getColumnNameByIndex(ColumnIndex) + rowNum;
sheet.mergeCells(startCellName, preCellName);
i = k - 1; //从k开始继续
}
break;
} else if (k == LastRowNum) {
//连同最后一行合并
sheet.mergeCells(startCellName, currCellName);
//sheetMerge.push({ s: { r: i, c: ColumnIndex }, e: { r: LastRowNum, c: ColumnIndex } });
i = LastRowNum; //结束外层循环
break;
}
}
}
}
格式化日期,根据索引输出列名
//js转换 /Date(1464671903000)/ 格式的日期,转换成:2016-07-11
function getFDate(date) {
var d = eval('new ' + date.substr(1, date.length - 2));
var ar_date = [d.getFullYear(), d.getMonth() + 1, d.getDate()];
for (var i = 0; i < ar_date.length; i++) ar_date[i] = dFormat(ar_date[i]);
return ar_date.join('-');
}
function dFormat(i) {
return i < 10 ? "0" + i.toString() : i;
}
//Excel/Sheet根据索引输出列名,2020-04-09
function getColumnNameByIndex(i) {
var result = String.fromCharCode('A'.charCodeAt() + i % 26);
while (i >= 26) {
i /= 26;
i--;
result = String.fromCharCode('A'.charCodeAt() + i % 26) + result;
}
return result;
}
弹窗保存文件
//获取当前日期,2019-12-25
function getFullTime() {
var now = new Date();
var yy = now.getFullYear(); //年
var mm = now.getMonth() + 1; //月
var dd = now.getDate(); //日
var hh = now.getHours(); //时
var ii = now.getMinutes(); //分
var ss = now.getSeconds(); //秒
var ms = now.getMilliseconds(); //毫秒
var clock = yy + "-";
if (mm < 10) clock += "0";
clock += mm + "-";
if (dd < 10) clock += "0";
clock += dd + "-";
if (hh < 10) clock += "0";
clock += hh + "-";
if (ii < 10) clock += '0';
clock += ii + "-";
if (ss < 10) clock += '0';
clock += ss + "-";
clock += ms;
return clock; //获取当前日期
}
function saveAs(blob, fileName) {
//生成一个a标签
var a = document.createElement('a');
a.style.display = 'none';
a.download = fileName;
a.id = "aexport";
//生成一个label标签,用于触发a标签点击事件
var lb = document.createElement('label');
lb.
for = "aexport";
a.appendChild(lb);
//创建一个URL对象,指向Blob对象
var objectURL = window.URL.createObjectURL(blob);
a.href = objectURL;
//把a标签加入body
document.body.appendChild(a);
//触发a标签点击事件
lb.click();
//IE不支持createObjectURL,特殊处理
if (_isIE()) {
window.navigator.msSaveOrOpenBlob(blob, fileName);
}
//删除a标签
document.body.removeChild(a);
//回收内存
URL.revokeObjectURL(objectURL);
}
解析
读取本地Excel,生成workbook,方法一,使用{ type: 'binary' }
;
// 读取本地excel文件
function readWorkbookFromLocalFile(file, callback) {
var reader = new FileReader();
reader.onload = function(e) {
var data;
if (reader.result) {
//读取后内容,适用FireFox
data = reader.result;
} else {
//读取后内容,适用IE
data = reader.content;
}
var workbook =XLSX.read(data, { type: 'binary' });
if (callback) callback(workbook);
};
reader.readAsBinaryString(file);
}
//readAsBinaryString 兼容IE11,2020-04-03
//https://www.cnblogs.com/badprogrammer/p/10728024.html
if (!FileReader.prototype.readAsBinaryString) {
FileReader.prototype.readAsBinaryString = function(fileData) { //解决ie11 大文件堆栈溢出的问题(for arrayBufferToString)
var binary = "";
var pt = this;
var reader = new FileReader();
reader.onload = function(e) {
var bytes = new Uint8Array(reader.result);
var length = bytes.byteLength;
for (var i = 0; i < length; i++) {
binary += String.fromCharCode(bytes[i]);
}
pt.content = binary;
//console.log("binary length:" + binary.length);
pt.onload(pt); //页面内data取pt.content文件内容
}
reader.readAsArrayBuffer(fileData);
}
}
读取本地Excel,生成workbook,方法二,使用{ type: 'base64' }
;
function fixdata(data) { //文件流转BinaryString
var o = "",
l = 0,
w = 10240;
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)));
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
return o;
}
// 读取本地excel文件
function readWorkbookFromLocalFile(file, callback) {
var reader = new FileReader();
reader.onload = function(e) {
var data;
if (reader.result) {
//读取后内容,适用FireFox
data = reader.result;
} else {
//读取后内容,适用IE
data = reader.content;
}
var workbook = XLSX.read(btoa(fixdata(data)), { type: 'base64' });
if (callback) callback(workbook);
};
reader.readAsArrayBuffer(file);
}
处理表单内容
readWorkbookFromLocalFile(fileObj.files[0],readWorkbook);
function readWorkbook(workbook) {
var sheetNames = workbook.SheetNames; // 工作表名称集合
var worksheet = workbook.Sheets[sheetNames[0]]; // 这里我们只读取第一张sheet
var range = XLSX.utils.decode_range(worksheet['!ref']);
var ncols = range.e.c - range.s.c + 1,
nrows = range.e.r - range.s.r + 1;
//修改列名为批注内容
for (var i = 0; i < ncols; i++) {
var key = String.fromCharCode(65 + i) + '2';
worksheet[key].w = worksheet[key].c[0].t;
}
var json = XLSX.utils.sheet_to_json(worksheet);
//IE不支持,注释掉,2020-04-03
//var json = Object.values(XLSX.utils.sheet_to_row_object_array(worksheet));
/* DO SOMETHING HERE */
}
//Excel/Sheet根据索引输出列名,2020-04-09
function getColumnNameByIndex(i) {
var result = String.fromCharCode('A'.charCodeAt() + i % 26);
while (i >= 26) {
i /= 26;
i--;
result = String.fromCharCode('A'.charCodeAt() + i % 26) + result;
}
return result;
}
总结
- 本插件对浏览器要求较高,部分功能可能有兼容性问题,不支持xls;
- 替代方案一,NPOI,导出时在后端生成workbook,写入输出流在前端下载,项目参考;导入时在服务器读取流为DataTable,再用SqlBulkCopy批量复制到数据库,项目参考;
- 替代方案二,使用商业软件,Wijmo,
项目可参考https://www.cnblogs.com/likeFlyingFish/p/5794467.html;