前言

负责人 A】:当初报表局部基于接口的 Excel 的导入和导出性能有点慢,前端这边能不能实现一下这个性能,而后咱们在比对看看成果!

切图仔 B】: 接口这边不能优化一下吗?比方排查下慢的起因什么的。

负责人 A】:当初后端开发工作比拟重,解决的外围工作也多还会波及一些架构上的调整,所以想着前端这边能够解决一下,而后看看整体成果。

切图仔 B】: OK,试试 就 ~ Shi Shi ~

上面就基于 xlsx 这个第三方库封装一个 <ExcelUpload /> 组件实现表格导入,以及 json 数据导出 Excel 性能的 json2Excel() 工具办法。

抉择 xlsx 的起因如下图所示:

Excel 解析为 JSON

根本内容

组件成果和构造

组件内容是很简略的构造和视图,间接查看如下的页面成果和代码即可:

<template>  <input    type="file"    ref="excelRef"    :accept="props.accept"    @change="onChange"    class="excel"  />  <h1>解析数据:</h1>  <h2>    <code>{{ excelData }}</code>  </h2></template><script setup lang="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

  • 通过 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,这里取第一个 Sheet      const 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",};

    格式化如下:

外围代码如下:

<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,这里取第一个 Sheet      const 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);      return false;    }  };};// 文件变动时触发const onChange = (event) => {  // 获取文件对象  const file = event.target.files[0];  // 读取文件内容  readerExcel(file);  // 革除数据  clearFile();};</script>

JSON 导出为 Excel

根本构造

页面内容也非常简单,具体如下:

<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.tsimport * 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 的 name    Sheets: {      [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 来实现。

以上就是本文的全部内容,心愿上述内容能够给大家带来一些思路,能够在评论区奉献更优质的计划。