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