js-xlsx介绍
由SheetJS出品的js-xlsx是一款非常方便的只需要纯JS即可读取和导出excel的工具库,功能强大,支持格式众多,支持xls、xlsx、ods(一种OpenOffice专有表格文件格式)等十几种格式。本文全部都是以xlsx格式为例。
-
github地址:github.com/SheetJS/she…
-
官方文档:docs.sheetjs.com/
-
js-xlsx 官方文档:sheetjs.gitbooks.io/docs/#sheet…
-
npm xlsx地址:www.npmjs.com/package/xls…
官方工具类
其实上面这些代码都不需要我们手写,官方已经提供好了现成的工具类给我们使用,主要包括:
aoa_to_sheet: 这个工具类最强大也最实用了,将一个二维数组转成sheet,会自动处理number、string、boolean、date等类型数据;table_to_sheet: 将一个table dom直接转成sheet,会自动识别colspan和rowspan并将其转成对应的单元格合并;json_to_sheet: 将一个由对象组成的数组转成sheet
使用的技术
- xlsx 用于解析和编写各种电子表格。比如excel、csv、html文件
- xlsx-style 为xlsx库添加样式,比如字体颜色,大小,行宽等。但是只支持xlsx、xlsm、xlsb格式
- FileSaver.js 负责下载保存文件。对各种兼容性比较好,对跨域文件也有处理
- xlsx-style 只 支持16进制的ARGB颜色,比如:
{ rgb: "FFFFAA00" }。注意这里是没有#号的。- 添加背景色是使用fill的fgColor,而不是bgColor。这里需要驼峰编写。
js-xlsx使用
方式一
官网找到插件,dist目录下有很多个JS文件,一般情况下用xlsx.core.min.js就够了,xlsx.full.min.js则是包含了所有功能模块。
直接script标签引入即可
方式二
安装命令: npm install xlsx 引用:import XLSX from 'xlsx'
导出
1.操作dom导出
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>JS-XLSX Demo</title>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
</head>
<body>
<table id="data-table" border="1" width="50%">
<tbody>
<tr>
<td>编号</td>
<td>名称</td>
<td>价格</td>
<td>日期</td>
</tr>
<tr>
<td>1</td>
<td>《Java架构师》</td>
<td>¥78.5</td>
<td>2018-10-11</td>
</tr>
<tr>
<td>2</td>
<td>《Python入门到精通》</td>
<td>¥65.3</td>
<td>2019-03-22</td>
</tr>
<tr>
<td>3</td>
<td>《JavaScript高级教程》</td>
<td>¥89.4</td>
<td>2017-04-13</td>
</tr>
</tbody>
</table>
<p>
将上面表格的内容导出到Excel文件
</p>
<p>
<button onclick="exportExcel()">导出Excel</button>
<button onclick="noDomExportExcel()">不操作dom导出Excel</button>
</p>
<script type="text/javascript">
function exportExcel() {
// 获取表格的Dom对象
var elt = document.getElementById('data-table');
// 创建Excel工作簿,即一个Excel文件
var wb = XLSX.utils.table_to_book(elt, {
sheet: "SheetJS" // 工作表格名称
});
// 导出工作表
return XLSX.writeFile(wb, 'SheetJSTableExport.xlsx');
}
function exportExcel2() {
// 获取表格的Dom对象
var elt1 = document.getElementById('xgszjcb-tb');
var elt2 = document.getElementById('xqzjcbxtscb-tb');
var elt3 = document.getElementById('xqzjcbdrb-tb');
var elt4 = document.getElementById('xgszjsr-tb');
// 创建虚拟workbook
var wb = XLSX.utils.book_new();
// 把数据生成sheet
var sheet1 = XLSX.utils.table_to_sheet(elt1);
var sheet2 = XLSX.utils.table_to_sheet(elt2);
var sheet3 = XLSX.utils.table_to_sheet(elt3);
var sheet4 = XLSX.utils.table_to_sheet(elt4);
// 把sheet添加到workbook里
XLSX.utils.book_append_sheet(wb, sheet1, "县区直接成本-合计");
XLSX.utils.book_append_sheet(wb, sheet2, "县区直接成本-系统生成");
XLSX.utils.book_append_sheet(wb, sheet3, "县区直接成本-导入");
XLSX.utils.book_append_sheet(wb, sheet4, "县区直接收入-合计");
// 导出工作表
return XLSX.writeFile(wb, '县区公司.xlsx');
}
//不操作dom导出Excel
function noDomExportExcel() {
console.log('000000000');
// 使用 XLSX.utils.aoa_to_sheet(excleData);
const excleData = [
['周一', '周二', '周三', '周四', '周五'],
['语文', '数学', '历史', '政治', '英语'],
['数学', '数学', '政治', '英语', '英语'],
['政治', '英语', '历史', '政治', '数学'],
];
// 使用 XLSX.utils.json_to_sheet(excleData);
// const excleData = [
// { 周一: '语文', 周二: '数学', 周三: '历史', 周四: '政治', 周五: '英语' },
// { 周一: '数学', 周二: '数学', 周三: '政治', 周四: '英语', 周五: '英语' },
// { 周一: '政治', 周二: '英语', 周三: '历史', 周四: '政治', 周五: '数学' },
// ];
// 设置表格样式,!cols为列宽
const options = {
'!cols': [
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
]
};
// 制作工作表的方式有很多种,以数组和对象为例
// const worksheet: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(excleData);
// const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(excleData);
// const worksheet = XLSX.utils.json_to_sheet(excleData);
const worksheet = XLSX.utils.aoa_to_sheet(excleData);
// 使用指定的单元格作为起点插入数据,r:行, c:列,详情看官网文档
// XLSX.utils.sheet_add_aoa(worksheet, [[“数学”,“语文”], [“政治”,“语文”], [“历史”,“政治”], ], {origin: {r: 2, c: 5}});
worksheet['!cols'] = options['!cols']; // 设置每列的列宽,10代表10个字符,注意中文占2个字符
worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];
console.log('workshe', worksheet['!merges']);
// 新建一个工作簿
// const workbook: XLSX.WorkBook = XLSX.utils.book_new();
const workbook = XLSX.utils.book_new();//创建虚拟workbook
console.log('workbook: ', workbook);
/* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
/* 输出工作表, 由文件名决定的输出格式(book,xlsx文件名称)*/
XLSX.writeFile(workbook, '排庭表.xlsx');
}
</script>
</body>
</html>
2.操作data导出
import XLSX from 'xlsx'
fnExport () {
// 使用 XLSX.utils.aoa_to_sheet(excleData);
const excleData = [
['周一', '周二', '周三', '周四', '周五'],
['语文', '数学', '历史', '政治', '英语'],
['数学', '数学', '政治', '英语', '英语'],
['政治', '英语', '历史', '政治', '数学'],
];
// 使用 XLSX.utils.json_to_sheet(excleData);
// const excleData = [
// { 周一: '语文', 周二: '数学', 周三: '历史', 周四: '政治', 周五: '英语' },
// { 周一: '数学', 周二: '数学', 周三: '政治', 周四: '英语', 周五: '英语' },
// { 周一: '政治', 周二: '英语', 周三: '历史', 周四: '政治', 周五: '数学' },
// ];
// 设置表格样式,!cols为列宽
const options = {
'!cols': [
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
]
};
// 制作工作表的方式有很多种,以数组和对象为例
// const worksheet = XLSX.utils.json_to_sheet(excleData);
const worksheet = XLSX.utils.aoa_to_sheet(excleData);
// 使用指定的单元格作为起点插入数据,r:行, c:列,详情看官网文档
// XLSX.utils.sheet_add_aoa(worksheet, [[“数学”,“语文”], [“政治”,“语文”], [“历史”,“政治”], ], {origin: {r: 2, c: 5}});
worksheet['!cols'] = options['!cols']; // 设置每列的列宽,10代表10个字符,注意中文占2个字符
worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];//合并单元格
// 新建一个工作簿
const workbook = XLSX.utils.book_new();//创建虚拟workbook
/* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
/* 输出工作表, 由文件名决定的输出格式(book,xlsx文件名称)*/
XLSX.writeFile(workbook, '排庭表.xlsx');
}
3.blob对象导出
将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>JS-XLSX Demo</title>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
<script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>
<body>
<table id="data-table" border="1" width="50%">
<tbody>
<tr>
<td>编号</td>
<td>名称</td>
<td>价格</td>
<td>日期</td>
</tr>
<tr>
<td>1</td>
<td>《Java架构师》</td>
<td>¥78.5</td>
<td>2018-10-11</td>
</tr>
<tr>
<td>2</td>
<td>《Python入门到精通》</td>
<td>¥65.3</td>
<td>2019-03-22</td>
</tr>
<tr>
<td>3</td>
<td>《JavaScript高级教程》</td>
<td>¥89.4</td>
<td>2017-04-13</td>
</tr>
</tbody>
</table>
<p>
将上面表格的内容导出到Excel文件
</p>
<p>
<button onclick="blobUrlExportExcel()">blob对象借助URL导出Excel</button>
</p>
<script type="text/javascript">
//将一个sheet转成最终的excel文件的blob对象
function blobUrlExportExcel() {
let table1 = document.querySelector("#data-table")
let sheet = XLSX.utils.table_to_sheet(table1);//将一个table对象转换成一个sheet对象
this.openDownloadDialog(sheet2blob(sheet), '下载.xlsx');
}
// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
function sheet2blob(sheet, sheetName) {
sheetName = sheetName || 'sheet1';
var workbook = {
SheetNames: [sheetName],
Sheets: {}
};
workbook.Sheets[sheetName] = sheet; // 生成excel的配置项
var wopts = {
bookType: 'xlsx', // 要生成的文件类型
bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
type: 'binary'
};
var wbout = XLSX.write(workbook, wopts);
var blob = new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}); // 字符串转ArrayBuffer
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
return blob;
}
function openDownloadDialog(url, saveName) {
if (typeof url == 'object' && url instanceof Blob) {
url = URL.createObjectURL(url); // 创建blob地址
}
var aLink = document.createElement('a');
aLink.href = url;
aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
var event;
if (window.MouseEvent) event = new MouseEvent('click');
else {
event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
}
aLink.dispatchEvent(event);
}
</script>
</body>
</html>
4.结合FileSaver插件导出
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>JS-XLSX Demo</title>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
<script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>
<body>
<p>
<button onclick="blobExportExcel()">结合FileSaver插件导出Excel</button>
</p>
<script type="text/javascript">
function blobExportExcel() {
//
const excleData = [
['周一', '周二', '周三', '周四', '周五'],
['语文', '数学', '历史', '政治', '英语'],
['数学', '数学', '政治', '英语', '英语'],
['政治', '英语', '历史', '政治', '数学'],
];
const options = {
'!cols': [
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
]
};
// 制作工作表的方式有很多种,以数组和对象为例
const worksheet = XLSX.utils.aoa_to_sheet(excleData);
worksheet['!cols'] = options['!cols'];
// worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];
// 新建一个工作簿
const workbook = XLSX.utils.book_new();//创建虚拟workbook
/* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
//
let wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中,从文件保存器中导入
}
function s2ab(s) {
let buf = new ArrayBuffer(s.length);
let view = new Uint8Array(buf);
for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
}
</script>
</body>
</html>
导入
1.xlsx结合FileReader对象导入
- 下载js-xlsx到dist复制出xlsx.full.min.js引入到页面中\
- 然后通过FileReader对象读取文件利用js-xlsx转成json数据
FileReader共有4种读取方法:
readAsArrayBuffer(file):将文件读取为ArrayBuffer。readAsBinaryString(file):将文件读取为二进制字符串。readAsDataURL(file):将文件读取为Data URLreadAsText(file, [encoding]):将文件读取为文本,encoding缺省值为'UTF-8'
eg:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
</head>
<body>
<script>
var wb;//读取完成的数据
var rABS = false; //是否将文件读取为二进制字符串
function importFile(obj) {//导入
if (!obj.files) {
return;
}
var f = obj.files[0];
var reader = new FileReader();
reader.onload = function (e) {
var data = e.target.result;
if (rABS) {
wb = XLSX.read(btoa(fixdata(data)), {//手动转化
type: 'base64'
});
} else {
wb = XLSX.read(data, {
type: 'binary'//以二进制的方式读取
});
}
console.log('wb: ', wb);
//wb.SheetNames[0]是获取Sheets中第一个Sheet的名字
//wb.Sheets[Sheet名]获取第一个Sheet的数据
// XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { raw: false }); //以字符串形式读取。
console.log('XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]): ', XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
document.getElementById("demo").innerHTML = JSON.stringify(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
};
if (rABS) {
reader.readAsArrayBuffer(f);
} else {
reader.readAsBinaryString(f);
}
}
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;
}
</script>
<div id="import">
<p>导入模版</p>
<p> 请选择要选择导入的模版文件</p>
<input type="file" onchange="importFile(this)">
<div id="demo"></div>
</div>
</html>
xlsx-style 自定义导出样式
xlsx-style 为xlsx库添加样式,比如字体颜色,大小,行宽等。但是只支持xlsx、xlsm、xlsb格式
生成xlsx导出类。这里必须使用xlsx-style才能生成指定样式
let wbout = xlsxStyle.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
完整代码
<script>
//添加样式导出
function sheetStyleExportExcel() {
let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
var wb = XLSX.utils.book_new();//新建一个工作簿
XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
//
// 设置表格样式,!cols为列宽
const options = {
'!cols': [//将第1,2,3,4,5 列的宽度设为100px
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
]
};
sheet1['!cols'] = options['!cols']; // 设置每列的列宽,10代表10个字符,注意中文占2个字符
sheet1['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];//合并单元格
//
// var style = {
// // 表头样式
// hs: {
// font: { sz: 10, color: { rgb: "ff0000" }, bold: true },
// alignment: { horizontal: "center", vertical: "center", wrapText: true },
// fill: { bgColor: { indexed: 64 }, fgColor: { rgb: "FFFF00" } },
// },
// // 内容样式
// bs: {
// font: { sz: 11 },
// alignment: { horizontal: "center", vertical: "center", wrapText: true },
// },
// // 注释行样式
// ts: {
// font: { sz: 10, bold: true },
// alignment: { vertical: "center", wrapText: true },
// fill: { bgColor: { indexed: 64 }, fgColor: { rgb: "00B050" } }
// }
// };
//
sheet2['A1'].s = {
fill: {
fgColor: { rgb: 'FFA3F4B1' } // 添加背景色
},
font: {
sz: 18, //18号字体
bold: true, //加粗
color: {
rgb: 'FF4F81BD' //字体颜色
},
},
alignment: {
horizontal: 'center' //水平居中对其
},
}
//
let wbout = xlsxStyle.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' });
// let wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中
}
</script>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
<script type="text/javascript" src='./libs/FileSaver.js'></script>
<script type="text/javascript" src='./libs/xlsxStyle.core.min.js'></script>
export(data, config, title = '导出文件名称') {
const sheet = 'sheet1'
const wb = XLSX.utils.book_new();
const ws = XLSX.utils.aoa_to_sheet(data);
XLSX.utils.book_append_sheet(wb, ws, sheet);
// 合并单元格
if (config ?.mergeCells ?.length) {
let mergeObj = []
config.mergeCells.forEach((element, i) => {
let _obj = {
s: {
c: element.col,
r: element.row
},
e: {
c: element.col + (element.colspan - 1),
r: element.row + (element.rowspan - 1)
}
}
mergeObj.push(_obj)
});
XSU.mergeCellsByObj(wb, sheet, mergeObj);
}
XSU.setAlignmentHorizontalAll(wb, sheet, 'center');//垂直居中
XSU.setAlignmentVerticalAll(wb, sheet, 'center');//水平居中
XSU.setAlignmentWrapTextAll(wb, sheet, true)//自动换行
XSU.setBorderDefaultAll(wb, sheet)//单元格默认边框
const wbout = xlsxStyle.write(wb, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), title + '.xlsx');
}
xlsx 导出多个sheet
方式1:
- 借助FileSaver插件中的saveAs方法
eg:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>JS-XLSX Demo</title>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
<script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>
<body>
<button onclick="sheetExportExcel()">结合saveAs多sheet导出Excel</button>
<script type="text/javascript">
function sheetExportExcel() {
let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
var wb = XLSX.utils.book_new();//新建一个工作簿
XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
//
let wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中
}
</script>
</body>
</html>
方式2:
- 把workbook转成blob
- 利用a标签和createObjectURL实现下载功能
eg:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>JS-XLSX Demo</title>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
<script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>
<body>
<button onclick="sheetExportExcel()">多sheet导出Excel</button>
<script type="text/javascript">
function sheetExportExcel() {
let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
var wb = XLSX.utils.book_new();//新建一个工作簿
XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
//
const workbookBlob = workbook2blob(wb); // 将workbook装化成blob对象
openDownloadDialog(workbookBlob, `部门统计.xlsx`);
}
// 将workbook装化成blob对象
function workbook2blob(workbook) {
// 生成excel的配置项
var wopts = {
// 要生成的文件类型
bookType: "xlsx",
// // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
bookSST: false,
type: "binary"
};
var wbout = XLSX.write(workbook, wopts);
// 将字符串转ArrayBuffer
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
}
var blob = new Blob([s2ab(wbout)], {
type: "application/octet-stream"
});
return blob;
}
//将blob对象创建bloburl,然后用a标签实现弹出下载框
function openDownloadDialog(url, saveName) {
if (typeof url == 'object' && url instanceof Blob) {
url = URL.createObjectURL(url); // 创建blob地址
}
var aLink = document.createElement('a');
aLink.href = url;
aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
var event;
if (window.MouseEvent) event = new MouseEvent('click');
else {
event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
}
aLink.dispatchEvent(event);
}
</script>
</body>
</html>
导出excel的逻辑
-
excel整个表格专业名词是
workbook,里面每张表格是sheet -
页面引入xlsx的库,
https://unpkg.com/xlsx/dist/xlsx.core.min.js -
把数据生成sheet,
var sheet = XLSX.utils.json_to_sheet(jsonData),json_to_sheet是将由对象组成的数组转化成sheet,当然还有 aoa_to_sheet将一个二维数组转成sheet 和 table_to_sheet将table的dom直接转成sheet -
创建虚拟的workbook,
var wb = XLSX.utils.book_new() -
把sheet添加到workbook里,
XLSX.utils.book_append_sheet(wb, sheet, "这里是sheetName"); -
把workbook转成blob
-
利用a标签和createObjectURL实现下载功能 或 FileSaver插件的saveAs下载
完整的测试代码
1.export
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>JS-XLSX Demo</title>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
<script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>
<body>
<table id="data-table" border="1" width="50%">
<tbody>
<tr>
<td>编号</td>
<td>名称</td>
<td>价格</td>
<td>日期</td>
</tr>
<tr>
<td>1</td>
<td>《Java架构师》</td>
<td>¥78.5</td>
<td>2018-10-11</td>
</tr>
<tr>
<td>2</td>
<td>《Python入门到精通》</td>
<td>¥65.3</td>
<td>2019-03-22</td>
</tr>
<tr>
<td>3</td>
<td>《JavaScript高级教程》</td>
<td>¥89.4</td>
<td>2017-04-13</td>
</tr>
</tbody>
</table>
<p>
将上面表格的内容导出到Excel文件
</p>
<p>
<button onclick="exportExcel()">导出Excel</button>
<button onclick="noDomExportExcel()">不操作dom导出Excel</button>
<button onclick="blobUrlExportExcel()">blob对象借助URL导出Excel</button>
<button onclick="blobExportExcel()">blob对象导出Excel</button>
<button onclick="sheetExportExcel()">结合saveAs多sheet导出Excel</button>
<button onclick="sheetBlobExportExcel()">多sheet导出Excel</button>
</p>
<script type="text/javascript">
function exportExcel() {
// 获取表格的Dom对象
var elt = document.getElementById('data-table');
// 创建Excel工作簿,即一个Excel文件
var wb = XLSX.utils.table_to_book(elt, {
sheet: "SheetJS" // 工作表格名称
});
// 导出工作表
return XLSX.writeFile(wb, 'SheetJSTableExport.xlsx');
}
function exportExcel2() {
// 获取表格的Dom对象
var elt1 = document.getElementById('xgszjcb-tb');
var elt2 = document.getElementById('xqzjcbxtscb-tb');
var elt3 = document.getElementById('xqzjcbdrb-tb');
var elt4 = document.getElementById('xgszjsr-tb');
// 创建虚拟workbook
var wb = XLSX.utils.book_new();
// 把数据生成sheet
var sheet1 = XLSX.utils.table_to_sheet(elt1);
var sheet2 = XLSX.utils.table_to_sheet(elt2);
var sheet3 = XLSX.utils.table_to_sheet(elt3);
var sheet4 = XLSX.utils.table_to_sheet(elt4);
// 把sheet添加到workbook里
XLSX.utils.book_append_sheet(wb, sheet1, "县区直接成本-合计");
XLSX.utils.book_append_sheet(wb, sheet2, "县区直接成本-系统生成");
XLSX.utils.book_append_sheet(wb, sheet3, "县区直接成本-导入");
XLSX.utils.book_append_sheet(wb, sheet4, "县区直接收入-合计");
// 导出工作表
return XLSX.writeFile(wb, '县区公司.xlsx');
}
//不操作dom导出Excel
function noDomExportExcel() {
// 使用 XLSX.utils.aoa_to_sheet(excleData);
const excleData = [
['周一', '周二', '周三', '周四', '周五'],
['语文', '数学', '历史', '政治', '英语'],
['数学', '数学', '政治', '英语', '英语'],
['政治', '英语', '历史', '政治', '数学'],
];
// 使用 XLSX.utils.json_to_sheet(excleData);
// const excleData = [
// { 周一: '语文', 周二: '数学', 周三: '历史', 周四: '政治', 周五: '英语' },
// { 周一: '数学', 周二: '数学', 周三: '政治', 周四: '英语', 周五: '英语' },
// { 周一: '政治', 周二: '英语', 周三: '历史', 周四: '政治', 周五: '数学' },
// ];
// 设置表格样式,!cols为列宽
const options = {
'!cols': [
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
]
};
// 制作工作表的方式有很多种,以数组和对象为例
// const worksheet: XLSX.WorkSheet = XLSX.utils.aoa_to_sheet(excleData);
// const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(excleData);
// const worksheet = XLSX.utils.json_to_sheet(excleData);
const worksheet = XLSX.utils.aoa_to_sheet(excleData);
// 使用指定的单元格作为起点插入数据,r:行, c:列,详情看官网文档
// XLSX.utils.sheet_add_aoa(worksheet, [[“数学”,“语文”], [“政治”,“语文”], [“历史”,“政治”], ], {origin: {r: 2, c: 5}});
worksheet['!cols'] = options['!cols']; // 设置每列的列宽,10代表10个字符,注意中文占2个字符
worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];
console.log('workshe', worksheet['!merges']);
// 新建一个工作簿
// const workbook: XLSX.WorkBook = XLSX.utils.book_new();
const workbook = XLSX.utils.book_new();//创建虚拟workbook
console.log('workbook: ', workbook);
/* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
/* 输出工作表, 由文件名决定的输出格式(book,xlsx文件名称)*/
XLSX.writeFile(workbook, '排庭表.xlsx');
}
//将一个sheet转成最终的excel文件的blob对象
function blobUrlExportExcel() {
let table1 = document.querySelector("#data-table")
let sheet = XLSX.utils.table_to_sheet(table1);//将一个table对象转换成一个sheet对象
this.openDownloadDialog(sheet2blob(sheet), '下载.xlsx');
}
// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
function sheet2blob(sheet, sheetName) {
sheetName = sheetName || 'sheet1';
var workbook = {
SheetNames: [sheetName],
Sheets: {}
};
workbook.Sheets[sheetName] = sheet; // 生成excel的配置项
var wopts = {
bookType: 'xlsx', // 要生成的文件类型
bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
type: 'binary'
};
var wbout = XLSX.write(workbook, wopts);
var blob = new Blob([s2ab(wbout)], {
type: "application/octet-stream"
}); // 字符串转ArrayBuffer
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
return blob;
}
//将blob对象创建bloburl,然后用a标签实现弹出下载框
function openDownloadDialog(url, saveName) {
if (typeof url == 'object' && url instanceof Blob) {
url = URL.createObjectURL(url); // 创建blob地址
}
var aLink = document.createElement('a');
aLink.href = url;
aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
var event;
if (window.MouseEvent) event = new MouseEvent('click');
else {
event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
}
aLink.dispatchEvent(event);
}
//blobExportExcel
function blobExportExcel() {
//
const excleData = [
['周一', '周二', '周三', '周四', '周五'],
['语文', '数学', '历史', '政治', '英语'],
['数学', '数学', '政治', '英语', '英语'],
['政治', '英语', '历史', '政治', '数学'],
];
const options = {
'!cols': [
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
{ wpx: 100 },
]
};
// 制作工作表的方式有很多种,以数组和对象为例
const worksheet = XLSX.utils.aoa_to_sheet(excleData);
worksheet['!cols'] = options['!cols'];
// worksheet['!merges'] = [{ e: { c: 1, r: 1 }, s: { c: 0, r: 0 } }];
// 新建一个工作簿
const workbook = XLSX.utils.book_new();//创建虚拟workbook
/* 将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)*/
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
//
let wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中
}
function s2ab(s) {
let buf = new ArrayBuffer(s.length);
let view = new Uint8Array(buf);
for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
}
//
function sheetExportExcel() {
let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
var wb = XLSX.utils.book_new();//新建一个工作簿
XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
//
let wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), `测试.xlsx`);//saveAs方法存在于FileSaver插件中
}
function sheetBlobExportExcel() {
let sheet1data = [{ department: "行政部", count: 2 }, { department: "前端部", count: 2 }];
let sheet2data = [{ name: "张三", do: "整理文件" }, { name: "李四", do: "打印" }];
let sheet3data = [{ name: "张大人", do: "vue" }, { name: "李大人", do: "react" }];
var sheet1 = XLSX.utils.json_to_sheet(sheet1data);//新建一个工作表
var sheet2 = XLSX.utils.json_to_sheet(sheet2data);
var sheet3 = XLSX.utils.json_to_sheet(sheet3data);
var wb = XLSX.utils.book_new();//新建一个工作簿
XLSX.utils.book_append_sheet(wb, sheet1, "部门统计");//将工作表添加到工作簿,生成xlsx文件(book,sheet数据,sheet命名)
XLSX.utils.book_append_sheet(wb, sheet2, "行政部");
XLSX.utils.book_append_sheet(wb, sheet3, "前端部");
//
const workbookBlob = workbook2blob(wb); // 将workbook装化成blob对象
openDownloadDialog(workbookBlob, `部门统计.xlsx`);
}
// 将workbook装化成blob对象
function workbook2blob(workbook) {
// 生成excel的配置项
var wopts = {
// 要生成的文件类型
bookType: "xlsx",
// // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
bookSST: false,
type: "binary"
};
var wbout = XLSX.write(workbook, wopts);
// 将字符串转ArrayBuffer
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
}
var blob = new Blob([s2ab(wbout)], {
type: "application/octet-stream"
});
return blob;
}
</script>
</body>
</html>
2.import
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="text/javascript" src='./libs/xlsx.full.min.js'></script>
<script type="text/javascript" src='./libs/FileSaver.js'></script>
</head>
<body>
<script>
function importFile(obj) {//导入
console.log('obj: ', obj);
console.log('obj.files: ', obj.files);
if (!obj.files) {
return;
}
// alert(obj.files[0].name);文件名
var f = obj.files[0];
var reader = new FileReader();
reader.onload = function (e) {
var data = e.target.result;
var wb = XLSX.read(data, {
type: 'binary' //以二进制的方式读取
});
var sheet0 = wb.Sheets[wb.SheetNames[0]];//sheet0代表excel表格中的第一页
var str = XLSX.utils.sheet_to_json(sheet0);//利用接口实现转换。
var templates = new Array();
var str1 = obj.files[0].name;
templates = str1.split(".");//将导入文件名去掉后缀
console.log('JSON.stringify(str): ', JSON.stringify(str));
// window.localStorage.setItem(templates[0], JSON.stringify(str))//存入localStorage 中
}
reader.readAsBinaryString(f);
}
// FileReader共有4种读取方法:
// 1.readAsArrayBuffer(file) :将文件读取为ArrayBuffer。
// 2.readAsBinaryString(file) :将文件读取为二进制字符串
// 3.readAsDataURL(file) :将文件读取为Data URL
// 4.readAsText(file, [encoding]) :将文件读取为文本,encoding缺省值为'UTF-8'
var wb;//读取完成的数据
var rABS = false; //是否将文件读取为二进制字符串
function importFile1(obj) {//导入
if (!obj.files) {
return;
}
var f = obj.files[0];
var reader = new FileReader();
reader.onload = function (e) {
var data = e.target.result;
if (rABS) {
wb = XLSX.read(btoa(fixdata(data)), {//手动转化
type: 'base64'
});
} else {
wb = XLSX.read(data, {
type: 'binary'//以二进制的方式读取
});
}
console.log('wb: ', wb);
//wb.SheetNames[0]是获取Sheets中第一个Sheet的名字
//wb.Sheets[Sheet名]获取第一个Sheet的数据
// XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], { raw: false }); //以字符串形式读取。
console.log('XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]): ', XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
document.getElementById("demo").innerHTML = JSON.stringify(XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]));
};
if (rABS) {
reader.readAsArrayBuffer(f);
} else {
reader.readAsBinaryString(f);
}
}
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;
}
</script>
<div id="import">
<p>导入模版</p>
<p> 请选择要选择导入的模版文件</p>
<input type="file" onchange="importFile(this)">
<input type="file" onchange="importFile1(this)">
<div id="demo"></div>
</div>
</body>
</html>