库:Excel.js(版本4.3.0) 和 FileSaver(版本2.0.5)
CDN地址:
html
<script src="https://cdn.bootcdn.net/ajax/libs/exceljs/4.3.0/exceljs.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2.0.5/FileSaver.js"></script>
Excel.js 中文文档:https://gitee.com/alan_scut/exceljs
先看一下效果吧
代码:
使用方法: exportExcal()
javascript
// 住宿安排(动态列)
var stay_arr = ['27日晚', '28日晚'];
// 内容数据
var test_data = [
{
"guest": "生态伙伴",
"name": "姓名一",
"sex": "男",
"company": "AAAAAA股份有限公司",
"job": "业务部部长",
"phone": "12345678912",
"stay": ["28日晚"]
},
{
"guest": "生态伙伴",
"name": "姓名二",
"sex": "女",
"company": "AAAAAA股份有限公司",
"job": "业务部部长",
"phone": "12345678912",
"stay": ["27日晚","28日晚",]
}
];
// 导出Excel
function exportExcal() {
// 文件名称
var fileName = 'simple.xlsx';
// 固定内容的列数
var basic_col_num = 7;
// 总列数(固定列+住宿动态列的长度)
var all_column_num = basic_col_num + stay_arr.length;
// 表单数据数组
var data_arr = [];
// 数据单元格起始行数
var rowStart = 4;
// 基础单元格边框样式
var borderStyle = {
top: { style: "thin", color: { argb: "FF000000" } },
left: { style: "thin", color: { argb: "FF000000" } },
bottom: { style: "thin", color: { argb: "FF000000" } },
right: { style: "thin", color: { argb: "FF000000" } },
}
// 基础内容对齐方式
var basicAlignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
// 新建工作簿
var wb = new ExcelJS.Workbook();
// 设置工作簿属性
wb.creator = 'Me'; // 作者
wb.lastModifiedBy = 'Her'; // 最后修改人
wb.created = new Date(2023, 10, 10); // 创建时间
wb.modified = new Date(); // 修改时间
wb.lastPrinted = new Date(2023, 10, 10); // 上次打印文档时间
wb.properties.date1904 = true; // 将工作簿日期设置为1904日期系统
// 向新的工作簿中增加一张工作表
var ws = wb.addWorksheet('邀约名单');
// 设置默认行高
ws.properties.defaultRowHeight = 20;
// 也可以在添加工作表的时候直接设置参数
// var ws = wb.addWorksheet('邀约名单', {properties:{defaultRowHeight:20}});
// 表头部分开始
// 设置单元格第一行
// 获取单元格内第一行
var collectRow = ws.getRow(1);
// 设置单行行高
collectRow.height = 40;
// 设置整行的文字样式
collectRow.style.font = { name: 'Microsoft YaHei', size: 16, bold: true, color: { argb: "ffffffff" } };
// 设置整行内容对齐方式
collectRow.alignment = basicAlignment;
// 获取A1单元格
var collectcell = ws.getCell(`A1`);
// 表格第一行标题内容,A1合并后填充的内容
collectcell.value = `参会信息统计表`;
// 设置单个单元格的背景色(这里不能设置整行,因为会超出数据的宽度)
collectcell.fill = {
type: "pattern",
pattern: "solid",
fgColor: { argb: "ff538dd5" },
}
// 设置单个单元格的边框样式
collectcell.border = {
top: { style: "thin", color: { argb: "FF000000" } },
left: { style: "thin", color: { argb: "FF000000" } },
right: { style: "thin", color: { argb: "FF000000" } },
};
// 合并单元格,将A1与H1合并(ws.mergeCells(`A1:H1`);)
ws.mergeCells(`A1:${getLetter(all_column_num)}1`);
// 设置单元格第二行
// 获取单元格内第二行
var collectRow = ws.getRow(2);
// 设置单行行高
collectRow.height = 26;
// 获取A2单元格
var collectcell2 = ws.getCell(`A2`);
// 表格第二行标题内容,A2合并后填充的内容
collectcell2.value = `活动时间:2023年10月10日 活动地点:XXXXXXX会议中心 住宿酒店:XXXX酒店`;
// 单独设置单元格的文字样式
collectcell2.font = { name: 'Microsoft YaHei', size: 10, bold: false, color: { argb: "ffffffff" } }; // 字体
// 单独设置单元格的背景色
collectcell2.fill = {
type: "pattern",
pattern: "solid",
fgColor: { argb: "ff538dd5" },
}
// 单独设置单元格的内容对齐方式
collectcell2.alignment = basicAlignment;
// 单独设置单元格的边框样式
collectcell2.border = {
left: { style: "thin", color: { argb: "FF000000" } },
bottom: { style: "thin", color: { argb: "FF000000" } },
right: { style: "thin", color: { argb: "FF000000" } },
};
// 合并单元格,将A2与H2合并(ws.mergeCells(`A2:H2`);)
ws.mergeCells(`A2:${getLetter(all_column_num)}2`);
// 处理表单第三行第四行每个单元格表头内容
for (let i = 1; i <= all_column_num; i++) {
let r3cell = ws.getCell(`${getLetter(i)}3`); // 获取第三行的单元格
let r4cell = ws.getCell(`${getLetter(i)}4`); // 获取第三行的单元格
// 设置内容对齐方式
r3cell.alignment = basicAlignment;
r4cell.alignment = basicAlignment;
// 前面部分固定内容的表头设置
if (i <= basic_col_num) {
// 设置单元格样式
r3cell.border = borderStyle;
r3cell.fill = {
type: "pattern",
pattern: "solid",
fgColor: { argb: "ff808080" },
}
r3cell.font = { name: 'Microsoft YaHei', size: 11, bold: true, color: { argb: "ffffffff" } };
switch (i) {
case 1:
ws.getCell(`${getLetter(i)}3`).value = "序号";
// 设置单元格宽度(宽度单位是字符宽度,而不是像素宽度,中文是两个字符)
ws.getColumn(i).width = 6;
break;
case 2:
ws.getCell(`${getLetter(i)}3`).value = "嘉宾类别";
ws.getColumn(i).width = 16;
break;
case 3:
ws.getCell(`${getLetter(i)}3`).value = "姓名";
ws.getColumn(i).width = 10;
break;
case 4:
ws.getCell(`${getLetter(i)}3`).value = "性别";
ws.getColumn(i).width = 6;
break;
case 5:
ws.getCell(`${getLetter(i)}3`).value = "单位";
ws.getColumn(i).width = 40;
break;
case 6:
ws.getCell(`${getLetter(i)}3`).value = "职务";
ws.getColumn(i).width = 24;
break;
case 7:
ws.getCell(`${getLetter(i)}3`).value = "手机号";
ws.getColumn(i).width = 15;
break;
}
// 合并上下对应的单元格
ws.mergeCells(`${getLetter(i)}3:${getLetter(i)}4`);
} else {
// 这部分是动态的单元格
// 设置单元格宽度
ws.getColumn(i).width = 12;
// 住宿部分表头样式需要分开设置(因为不合并)
r3cell.border = borderStyle;
r3cell.fill = {
type: "pattern",
pattern: "solid",
fgColor: { argb: "ffebf1de" },
}
r4cell.border = borderStyle;
r4cell.fill = {
type: "pattern",
pattern: "solid",
fgColor: { argb: "ffebf1de" },
}
r4cell.font = { name: 'Microsoft YaHei', size: 11, bold: true, color: { argb: "ff595959" } };
// 住宿第三行的内容
if (i == (basic_col_num + 1)) {
ws.getCell(`${getLetter(i)}3`).value = "行程安排";
// 合并单元格(行程安排)
ws.mergeCells(`${getLetter(i)}3:${getLetter(i + stay_arr.length - 1)}3`);
}
// 设置住宿列第四行的动态内容
ws.getCell(`${getLetter(i)}4`).value = stay_arr[i - basic_col_num - 1];
}
}
// 处理表单数据
for (let i = 0; i < test_data.length; i++) {
// 序号,嘉宾类别,姓名,性别,单位,职务,手机号
data_arr[i] = [
i + 1,
test_data[i].guest,
test_data[i].name,
test_data[i].sex,
test_data[i].company,
test_data[i].job,
test_data[i].phone
]
// 动态添加住宿(循环住宿内容数组)
for (let j = 0; j < stay_arr.length; j++) {
if (test_data[i].stay) {
// 判断该值是否是列表中数据内存在的值
if (test_data[i].stay.indexOf(stay_arr[j]) != -1) {
data_arr[i].push("是");
} else {
data_arr[i].push("");
}
} else {
// 如果没有住宿,直接添加空
data_arr[i].push("");
}
}
}
// 将表单输入插入行
for (let i = 0; i < data_arr.length; i++) {
// 获取数据行
let r_data = ws.getRow(i + rowStart + 1);
// 设置整行单元格的内容对其方式
r_data.alignment = basicAlignment;
// 字体
r_data.font = { name: 'Microsoft YaHei', size: 11, bold: false, color: { argb: "ff000000" } };
// 设置整行的数据内容
r_data.values = data_arr[i];
// 循环本行插入的每个单元格,然后给单元格设置边框样式(注意,一定要插入数据后,才能循环设置)
// 这里不能用 设置整行边框,因为单元格会超出,不好看了
r_data.eachCell({ includeEmpty: true }, function (cell, colNumber) {
ws.getCell(`${getLetter(colNumber)}${i + rowStart + 1}`).border = borderStyle
});
}
// node端才能使用
// wb.xlsx.writeFile(fileName).then(() => {
// console.log('file created');
// }).catch(err => {
// console.log(err.message);
// });
wb.xlsx.writeBuffer().then(buffer => {
// 这里之前是 FileSaver.saveAs 因为报错换成 window.saveAs 原因文章后面有说
window.saveAs(new Blob([buffer], { type: 'application/octet-stream' }), `${fileName || 'excel.xlsx'}`);
})
}
// 获取第N个字母
function getLetter(num) {
return String.fromCharCode(64 + num);
}
代码中用到的方法总结:
新建工作簿 & 向工作簿中增加一张工作表
var workbook = new ExcelJS.Workbook();
var worksheet = workbook.addWorksheet('邀约名单');
合并单元格(将A1与H1合并)
worksheet.mergeCells('A1:H1');
获取行(第一行)
var collectRow = worksheet.getRow(1);
获取列(B或者3)
var collectcell = worksheet.getColumn('B');
var collectcell = worksheet.getColumn(3);
获取单元格(A2)
var collectcell = worksheet.getCell('A2');
设置单元格内容(行、列、单元格均可设置。行、列是赋值数组)
var collectcell = worksheet.getCell('A2');
collectcell.value = '活动时间';
设置单元格宽度(列、单元格均可设置。宽度单位是字符宽度,而不是像素宽度,中文是两个字符。)
var collectcell = worksheet.getCell('A2');
collectcell.width = 6;
设置工作表的默认行高
worksheet.properties.defaultRowHeight = 20;
设置工作表的默认列宽
worksheet.properties.defaultColWidth = 50;
设置文字样式(行,列,单元格均可设置)
var collectcell = worksheet.getCell('A2');
collectcell.font = { name: 'Microsoft YaHei', size: 10, bold: false, color: { argb: "ffffffff" } };
设置背景色(行,列,单元格均可设置)
var collectcell = worksheet.getCell('A2');
collectcell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "ff538dd5" } };
设置内容对齐方式(行,列,单元格均可设置)
var collectcell = worksheet.getCell('A2');
collectcell.alignment = {
top: { style: "thin", color: { argb: "FF000000" } },
left: { style: "thin", color: { argb: "FF000000" } },
bottom: { style: "thin", color: { argb: "FF000000" } },
right: { style: "thin", color: { argb: "FF000000" } },
}
循环行内的每一个单元格(包括空单元格)
let r_data = ws.getRow(i + rowStart + 1);
// 循环本行插入的每个单元格,然后给单元格设置边框样式(注意,一定要插入数据后,才能循环设置)
r_data.eachCell({ includeEmpty: true }, function (cell, colNumber) {
console.log('Cell ' + colNumber + ' = ' + cell.value);
});
遇见的一些问题:
1. 报错:FileSaver.saveAs is not a function.saveAs is not a function
解决方法: 将 FileSaver.saveAs
改成 window.saveAs
即可(原因是 FileSaver 是全局引用了)
2. 为什么不直接用 wb.xlsx.writeFile
答:因为 wb.xlsx.writeFile
只能 node
用,所以需要用 FileSaver
。
3. eachCell
为什么会无效(不进入循环)
答:一定要插入数据后,才能循环,没有插入数据的时候是无法进入循环的。