exceljs導出導入Excel


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM