Recently, I often do irregular
Excel
imports, or some commonExcel
exports. At present, the above mentioned are pure front-end implementations; let’s talk about the frequently used Excel export and import implementation schemes. This article implements the technology stack with Vue2 + JS as an example
Import categories:
- Calling
API
The data is completely parsed and cleaned by the backend, and the frontend is only responsible for callingAPI
;- The front end parses
Excel
, cleans the data, and processes the corresponding data into theAPI
required JSON; (this article mainly introduces this)
Export categories:
- The call
API
is completely generated by the backendExcel
, and the frontend obtainsAPI
the returned file name and downloads it;- The front end is generated based on JSON data , and then downloaded
Excel
using a third-party library ; (this article mainly introduces this)file-saver
Import Excel
needs to use xlsx
this npm library
Export Excel
needs to be used exceljs
, file-saver
these two
Just npm install the corresponding library directly;
1. Import Excel and process data
1.1 Requirement Example
If I now have an Excel of this kind that needs to be imported, the front end is responsible for parsing the Excel and cleaning the data, and the API only needs 4-5 useful fields
1.2 Specific implementation – html part
<section>
<el-button @click="handleUpload" size="mini" type="primary">{
{l("ChooseFile")}}</el-button>
<input v-show="false" @change="handleFileChange" ref="inputFile" type="file" />
<el-alert type="warning" :closable="false" style="margin-top:6px;">
{
{'Please Upload (xls | xlsx) Type File'}}
</el-alert>
</section>
import XLSX from "xlsx";
handleUpload() {
if (!this.importResult) {
this.$refs["inputFile"].click();
}
},
handleFileChange(e) {
const file = e.target.files[0];
const fileName = file.name.substring(file.name.lastIndexOf(".") + 1);
if (fileName !== "xlsx" && fileName !== "xls") {
this.$message.error(this.l("FileTypeError,PleaseTryAgain"));
return;
}
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = (e) => {
const result = e.target.result;
if (!result) {
this.errorMsg = this.l("NoData");
this.step = 1;
return;
}
if (this.importType === 1) {
this.handleSinglePageExcel(result);
} else {
this.handleMultiplePageExcel(result);
}
};
reader.onerror = (err) => {
throw new Error("UpLoadError: " + err.stack);
};
},
1.3 Specific implementation – single sheet
handleSinglePageExcel(data) {
const wb = XLSX.read(data, {
type: "binary",
cellDates: true,
});
const sheet = wb.SheetNames[0];
const importData = XLSX.utils.sheet_to_json(wb.Sheets[sheet], {
range: -1,
});
const arr = [];
for (let i = 3; i < importData.length; i++) {
// 处理业务逻辑
}
this.importResult = arr;
},
1.4 Specific implementation – multiple sheets
handleMultiplePageExcel(data) {
const wb = XLSX.read(data, {
type: "binary",
cellDates: true,
});
const sheetList = wb.SheetNames;
const arrMap = {
}; // 多 Sheet 页数据;
sheetList.forEach((t) => {
const importData = XLSX.utils.sheet_to_json(wb.Sheets[t], {
range: 2,
});
arrMap[t] = importData;
});
const arr = [];
for (let t in arrMap) {
const importData = arrMap[t];
// importData : 代表每个 Sheet 页的 Excel 数据
}
this.importResult = arr;
},
1.4 Related parameters
file read type
type | expected input |
---|---|
base64 | Base64 encoded type string |
binary | binary string (byte n is data.charCodeAt(n)) |
string | JS string (only for UTF-8 text format) |
buffer | The buffer type of nodejs |
array | array |
file | The path to the file that will be read (nodejs only) |
common method
sheet_to_*
The function accepts a worksheet and an optional options object, mainly to convert the excel file into the corresponding data format, generally used when importing the excel file*_to_sheet
The function accepts a data object and an optional options object, mainly to convert the data format into an excel file, which is generally used when exporting filessheet_add_*
Function accepts worksheet, data and optional options. The main purpose is to update an existing worksheet object
2. According to the existing data, export Excel as needed
1.1 Requirement Example
If I now have a query table of this kind that needs to be exported, because all the data is in the table, it
API
can be implemented without calling
1.2 Specific implementation
import {
Workbook } from "exceljs";
import {
saveAs } from "file-saver";
try {
this.loading = true;
// 创建一个工作簿
const workbook = new Workbook();
// columns 需要生成的Excel列 { prop, label, width, sheetName | Detail }
// sheetName 需要生成的 Sheet 页, 如果只生成一个 Sheet Excel 不用考虑这里
const sheets = _.uniq(this.columns.map((t) => t.sheetName || "Detail"));
for (let i = 0; i < sheets.length; i++) {
const columns = this.columns.filter(
(t) => (t.sheetName || "Detail") === sheets[i]
);
// addWorksheet 添加一个 Sheet 页
const worksheet = workbook.addWorksheet(sheets[i]);
worksheet.columns = columns.map((t) => {
// 需求处理
const label = t.label ? t.label : this.propToLabel(t.prop);
return {
header: this.l(label), // Excel 第一行标题
key: t.prop,
width: label.length * 2, // Excel 列的宽度
};
});
// this.list -> 当前 table 数据
this.list.forEach((t) => {
const row = [];
columns.forEach((x) => {
row.push(t[x.prop] || "");
});
// 生成的 Excel Sheet 添加数据
worksheet.addRow(row);
});
// 第一行 Header 行添加自定义样式
worksheet.getRow(1).eachCell((cell, colNumber) => {
cell.fill = {
type: "pattern",
pattern: "solid",
fgColor: {
argb: "cccccc",
},
bgColor: {
argb: "#96C8FB",
},
};
});
}
// 导出的文件名
const code = this.exportTemple.code || new Date().getTime();
workbook.xlsx.writeBuffer().then((buffer) => {
// 调用 第三方库 下载刚生成好的Excel
saveAs(
new Blob([buffer], {
type: "application/octet-stream",
}),
code + "." + "xlsx"
);
this.loading = false;
});
} catch (e) {
console.error("clinet export error", e);
} finally {
this.loading = false;
}
If
大数据的量导出
it is recommended to implement it on the backend, the frontend shouldwebsocket
be optimized to avoid bad user experience caused by long-time loading