前言
【负责人 A
】:现在报表部分基于接口的 Excel
的导入和导出功能有点慢,前端这边能不能实现一下这个功能,然后我们在比对看看效果!
【切图仔 B
】: 接口这边不能优化一下吗?比如排查下慢的原因什么的。
【负责人 A
】:现在后端开发任务比较重,处理的核心任务也多还会涉及一些架构上的调整,所以想着前端这边可以处理一下,然后看看整体效果。
【切图仔 B
】: OK,试试 就 ~ Shi Shi ~
下面就基于 xlsx
这个第三方库封装一个 <ExcelUpload />
组件实现表格导入,以及 json
数据导出 Excel
功能的 json2Excel()
工具方法。
选择
xlsx
的原因如下图所示:
Excel 解析为 JSON
基本内容
组件效果和结构
组件内容是很简单的结构和视图,直接查看如下的页面效果和代码即可:
### Excel 数据格式
**`Excel`** 数据格式有两种,一种是 **有表头说明** 的,另一种是 **无表头说明** 的,具体内容如下:
* **有表头说明**<img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7ae907cd0b6f461da9560e4fca1ec32e~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?" style="margin: auto" />
* **无表头说明**<img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/320d6d696370430eb49e0d6b6e7f2c15~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?" style="margin: auto" />
实现 Excel 转 JSON 功能
------------------
### 核心步骤
* 通过 `FileReader` 以二进制的方式读取 `Excel` 文件,即 `fileReader.readAsBinaryString(file)`* 将对应的二进制数据通过 `XLSX.read(fileData, { type: "binary" })` 方法生成 `workbook` 对象* `workbook.SheetNames[0]` 获取第一个 `Sheet` 的名称 `wsname`,因为表格是有序列表,因此可以有多个 `Sheet`<img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b212194acd2845c885764ebdcf15fda2~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)* 通过 `XLSX.utils.sheet_to_json(workbook.Sheets[wsname])` 方法将对应的 `Sheet` 内容转换为 `JSON` 数据### 效果演" style="margin: auto" />
* **有表头说明**<img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/17bb66e17cba4018a8fd097accf6f352~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)   => {const fileReader = new FileReader();// 以二进制的方式读取表格内容fileReader.readAsBinaryString(file);// 表格内容读取完成fileReader.onload = (event: any) => {try {const fileData = event.target.result;const workbook = XLSX.read(fileData, {type: “binary”,});// 表格是有序列表,因此可以取多个 Sheet,这里取第一个 Sheetconst wsname = workbook.SheetNames[0];// 将表格内容生成 json 数据const sheetJson = XLSX.utils.sheet_to_json(workbook.Sheets[wsname]);console.log(sheetJson); // 得到的表格 JSON 内容} catch (e) {console.log(e);return false;}};
};
// 文件变化时触发
const onChange = (event) => {// 获取文件对象const file = event.target.files[0];// 读取文件内容readerExcel(file);// 清除数据clearFile();
};
const clearFile = () => {excelRef.value.value = “”;
};
格式化 JSON 数据
-----------
这里需要考虑 **有表头说明** 和 **无表头说明** 的情况,为了方便统一处理,作如下规定:
* 通过将 **有表头说明** 的数据格式统一转化为 **无表头说明** 的数据格式
* 统一将 **无表头说明** 的数据格式转化为标准的接口入参,即 `{ key: value }`,这里需要建立一个 `name -> key` 的映射关系:```const excelNameToKey = {'姓名': "name",'年龄': "age",'特长': "skill",'电话': "telephone",'地址': "address",}; ```**格式化如下:**
<img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/31ff6d40f6984d1e85a64854dfb18d45~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?" style="margin: auto" />
**核心代码如下:**
JSON 导出为 Excel
==============
基本结构
----
页面内容也非常简单,具体如下:
<img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ca0648a760bb4834a6e1cee3ba03f38a~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?)``" style="margin: auto" />
<template><div id="container"><h1>JSON 数据:</h1><h2><code>{{ jsonData }}</code></h2><button @click="exportExcel">导出 Excel</button></div>
</template>
导出功能
导出其实也很简单,首先创建 src/utils/json2Excel.ts
文件里面就是具体导出的实现,具体内容如下:
// src/utils/json2Excel.ts
import * as XLSX from "xlsx";
export default (data: any[],sheetName: string = "sheet1",fileName: string = "json2Excel.xlsx"
) => {const jsonWorkSheet = XLSX.utils.json_to_sheet(data);const workBook = {SheetNames: [sheetName], // 指定有序 sheet 的 nameSheets: {[sheetName]: jsonWorkSheet, // 表格数据内容},};return XLSX.writeFile(workBook, fileName); // 向文件系统写出文件
};
然后在 App.vue
中使用,具体如下:
// src/App.vue
<script setup lang="ts">
import json2Excel from "./utils/json2Excel";
// 测试的 JSON 数据
const jsonData = [{name: "张三1",age: 18,skill: "干饭1",telephone: 20200825,address: "宇宙尽头1",},{name: "张三2",age: 19,skill: "干饭2",telephone: 20200826,address: "宇宙尽头2",},{name: "张三3",age: 20,skill: "干饭3",telephone: 20200827,address: "宇宙尽头3",},{name: "张三4",age: 21,skill: "干饭4",telephone: 20200828,address: "宇宙尽头4",},{name: "张三5",age: 22,skill: "干饭5",telephone: 20200829,address: "宇宙尽头5",},{name: "张三6",age: 23,skill: "干饭6",telephone: 20200830,address: "宇宙尽头6",},{name: "张三7",age: 24,skill: "干饭7",telephone: 20200831,address: "宇宙尽头7",},{name: "张三8",age: 25,skill: "干饭8",telephone: 20200832,address: "宇宙尽头8",},{name: "张三9",age: 26,skill: "干饭9",telephone: 20200833,address: "宇宙尽头9",},{name: "张三10",age: 27,skill: "干饭10",telephone: 20200834,address: "宇宙尽头10",},
];
// key -> name 的映射
const excelKeyToName = {name: "姓名",age: "年龄",skill: "特长",telephone: "电话",address: "地址",
};
// 导出 Excel 文件
const exportExcel = () => {// 格式化参数const data = jsonData.map((item) => {const newItem: any = {};Object.keys(item).forEach(key => {newItem[excelKeyToName[key]] = item[key];});return newItem;});
// 导出 Exceljson2Excel(data);
};
</script>
效果演示

最后
以上只是实现了简单的单个导入、导出功能,可以将其完善为 批量操作,但是要注意批量操作带来的耗时性,将对应的耗时部分通过 webworker
等方式处理,这样页面就不需要一直等待当前的操作完成。
另外,如果有要求在导出 Excel
时有表格样式(如:行列宽高设置等)可以通过 xlsx-populate
来实现。
以上就是本文的全部内容,希望上述内容可以给大家带来一些思路,可以在评论区贡献更优质的方案。
最后
为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。
有需要的小伙伴,可以点击下方卡片领取,无偿分享