ARTICLE · 1342666
给我实现一个前端的 Excel 导入和导出功能
作者:熊的猫
原文:https://juejin.cn/post/7135945969425711111
【**负责人 A】:现在报表部分基于接口的 Excel 的导入和导出功能有点慢,前端这边能不能实现一下这个功能,然后我们在比对看看效果!**
【**切图仔 B**】:接口这边不能优化一下吗?比如排查下慢的原因什么的。
【**负责人 A】:现在后端开发任务比较重,处理的核心任务也多还会涉及一些架构上的调整,所以想着前端这边可以处理一下,然后看看整体效果。**
【**切图仔 B**】:OK,试试 就 ~ Shi Shi ~
下面就基于 **`xlsx`**[2] 这个第三方库封装一个 <ExcelUpload /> 组件实现表格导入,以及 json 数据导出 Excel 功能的 json2Excel() 工具方法。
选择 **`xlsx`**[3] 的原因如下图所示:
Excel 解析为 JSON
基本内容
组件效果和结构
组件内容是很简单的结构和视图,直接查看如下的页面效果和代码即可:
<template><inputtype="file"ref="excelRef":accept="props.accept" @change="onChange"class="excel" /><h1>解析数据:</h1><h2><code>{{ excelData }}</code></h2></template><scriptsetuplang="ts">import { reactive, ref } from'vue'import * as XLSX from'xlsx'interface Props {accept: string}const props = withDefaults(defineProps<Props>(), {accept:'.csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',})const excelRef: any = ref(null)const excelData: any[] = reactive([])const onChange = (event: any) => {// 获取文件对象const file = event.target.files[0]console.log(file)}</script>复制代码Excel 数据格式
Excel 数据格式有两种,一种是 有表头说明 的,另一种是 无表头说明 的,具体内容如下:
有表头说明
无表头说明
实现 Excel 转 JSON 功能
核心步骤
通过
FileReader以二进制的方式读取Excel文件,即fileReader.readAsBinaryString(file)将对应的二进制数据通过
XLSX.read(fileData, { type: "binary" })方法生成workbook对象workbook.SheetNames[0]获取第一个Sheet的名称wsname,因为表格是有序列表,因此可以有多个Sheetimage.png 通过
XLSX.utils.sheet_to_json(workbook.Sheets[wsname])方法将对应的Sheet内容转换为JSON数据
效果演示
有表头说明
无表头说明
具体代码
// 读取对应表格文件const readerExcel = (file: File) => {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);returnfalse; } };};// 文件变化时触发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",};复制代码
格式化如下:
核心代码如下:
<script setup lang='ts'>import { reactive, ref } from"vue";import * as XLSX from"xlsx";const excelNameToKey = { 姓名: "name", 年龄: "age", 特长: "skill", 电话: "telephone", 地址: "address",};interface Props {accept: string;}const props = withDefaults(defineProps<Props>(), {accept:".csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",});const excelRef: any = ref(null);const excelData: any[] = reactive([]);const clearFile = () => { excelRef.value.value = "";};// 标准化 JSON 数据const excelDataToJson = (sheetJson: any[]) => {if (!sheetJson.length) return;let result = sheetJson;const hasTableHead = !!sheetJson[0].__EMPTY;// 拥有表头的数据,需要取正确的值if (hasTableHead) {const header = sheetJson.shift();const data: any[] = [];Object.keys(header).forEach((key) => { sheetJson.forEach((item, index) => {const obj = data[index] || {}; obj[header[key]] = item[key]; data[index] = obj; }); });console.log("【】【】", data); result = data; }// 将表格对应的文字转换为 key result.forEach((item) => {const newItem: any = {};Object.keys(item).forEach((key) => { newItem.title = key; newItem[excelNameToKey[key]] = item[key]; }); excelData.push(newItem); });};// 读取对应表格文件const readerExcel = (file: File) => {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 数据 excelDataToJson(sheetJson); } catch (e) {console.log(e);returnfalse; } };};// 文件变化时触发const onChange = (event) => {// 获取文件对象const file = event.target.files[0];// 读取文件内容 readerExcel(file);// 清除数据 clearFile();};</script>复制代码JSON 导出为 Excel
基本结构
页面内容也非常简单,具体如下:
<template><divid="container"><h1>JSON 数据:</h1><h2><code> {{ jsonData }}</code></h2><button @click="exportExcel">导出 Excel</button></div></template>复制代码导出功能
导出其实也很简单,首先创建 src/utils/json2Excel.ts 文件里面就是具体导出的实现,具体内容如下:微信搜索公众号:架构师指南,回复:架构师 领取资料 。
// src/utils/json2Excel.tsimport * as XLSX from"xlsx";exportdefault ( 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; });// 导出 Excel json2Excel(data);};</script>复制代码效果演示
最后
以上只是实现了简单的单个导入、导出功能,可以将其完善为 批量操作,但是要注意批量操作带来的耗时性,将对应的耗时部分通过 webworker 等方式处理,这样页面就不需要一直等待当前的操作完成。
另外,如果有要求在导出 Excel 时有表格样式(如:行列宽高设置等)可以通过 **`xlsx-populate`**[4] 来实现。
以上就是本文的全部内容,希望上述内容可以给大家带来一些思路,可以在评论区贡献更优质的方案。
转载声明:所有转载文章必注明原文出处或转载出处(转载处未注明原文出处的情况),如有侵权请联系删除















































































