夜雨聆风学习资料网

ARTICLE · 1342666

给我实现一个前端的 Excel 导入和导出功能

给我实现一个前端的 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,因为表格是有序列表,因此可以有多个 Sheet

    image.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] 来实现。

以上就是本文的全部内容,希望上述内容可以给大家带来一些思路,可以在评论区贡献更优质的方案。

转载声明:所有转载文章必注明原文出处或转载出处(转载处未注明原文出处的情况),如有侵权请联系删除

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料