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;