前端开发与第三方库之间不得不说的故事—excel篇

前言

大家好,我是沐浴在曙光下的贰货道士 。今年计划出一个使用第三方库的专栏,介绍一些在项目中常用的第三方库。而今天迎来了我们的第一位主角 --- excel有喜欢本文的朋友,欢迎一键三连哦~

前端开发与excel之间不得不说的故事

a. excel解析数据

需求分析: 在某些场景下,前端需要将上传的excel文件解析为表格数据,并展示在页面上,这个时候就涉及到excel的解析(sheetjs官方github)。

首先,我们需要安装依赖:npm install xlsx。依赖安装完成后,就可以愉快地操作了:

html 复制代码
<template>
  <div class="app-container system-home">
    <el-upload 
      action="#" 
      :auto-upload="false" 
      accept=".xlsx,.xls" 
      :show-file-list="false" 
      :on-change="onChange"
    >
      <el-button size="small" type="primary">上传excel文件</el-button>
    </el-upload>
  </div>
</template>

<script>

import xlsx from 'xlsx'
// import * as xlsx from 'xlsx'(视版本而定)

export default {
  data() {
    return {
      excelData: []
    }
  },

  methods: {
    async onChange(file) {
      let dataBinary = await new Promise((resolve) => {
        `https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader`
        let reader = new FileReader()
        `将文件读取为二进制字符串`
        reader.readAsBinaryString(file.raw)
        reader.onload = (ev) => {
          `通过监听onload事件,在文件读取完成后,将结果解析为二进制字符串,并将其传递给resolve函数`
          resolve(ev.target.result)
        }
      })
      `将二进制字符串解析为工作簿,cellDates: true用于将日期单元格解析为日期对象`
      let workBook = xlsx.read(dataBinary, { type: 'binary', cellDates: true })
      `获取工作簿中第一个工作表Sheet的引用`
      let firstWorkSheet = workBook.Sheets[workBook.SheetNames[0]]
      `将工作表转换为JSON格式的数据,返回一个包含工作表数据的数组`
      const data = xlsx.utils.sheet_to_json(firstWorkSheet)
      `格式化数据,重置数组对象的key值`
      this.formatData(data)
    },

    formatData(data) {
      this.excelData = data.map((item) => ({
        singer: item['歌手'],
        song: item['歌名'],
        hot: item['热度(亿)']
      }))
      console.log('this.excelData', this.excelData)
    }
  }
}
</script>

假定我们上传的excel文件长这个样子:

点击页面上的上传excel文件按钮,并选择需要上传的excel文件,就会在控制台上显示我们需要获取的最终数据:

至于最后的表格数据展示,就靠广大掘友们自行发挥了~

b. excel导出

需求分析: 在某些场景下,需要前端将数据导出为excel文件(FileSaver.js官方github)。

除了需要安装xlsx依赖外,我们还需要安装依赖:npm install file-saver。依赖安装完成后,就可以愉快地操作了。

1. 前端导出表格上的数据

html 复制代码
<template>
  <div class="app-container system-home">
    <loading-btn 
      type="primary" 
      size="mini" 
      @click="exportHandler(formatData(excelData), 'songs.xlsx')"
    >
      导出为excel文件
    </loading-btn>
  </div>
</template>

<script>
import xlsx from 'xlsx'
// import * as xlsx from 'xlsx'(视版本而定)
import { saveAs } from 'file-saver'

export default {
  data() {
    return {
     `假定这些数据是需要我们前端导出的表格数据: `
     excelData: [
        {
          singer: '周杰伦',
          song: '搁浅',
          hot: '1300.46'
        },
        {
          singer: '周杰伦',
          song: '退后',
          hot: '999.99'
        },
        {
          singer: '周杰伦',
          song: '说了再见',
          hot: '1221.67'
        },
        {
          singer: '周杰伦',
          song: '最长的电影',
          hot: '2004.79'
        },
        {
          singer: '周杰伦',
          song: '我落泪情绪零碎',
          hot: '2241.63'
        },
        {
          singer: '林俊杰',
          song: '圆圆圈圈',
          hot: '1200.24'
        },
        {
          singer: '林俊杰',
          song: '浪漫广西',
          hot: '666.66'
        },
        {
          singer: '华晨宇',
          song: '做法',
          hot: '0.00 '
        },
        {
          singer: '蔡徐坤',
          song: '只因你太美',
          hot: '99.86'
        }
      ]
    }
  },

  methods: {
    formatData(data) {
      return data.map(({ singer, song, hot }) => ({
        '歌手': singer,
        '歌名': song,
        '热度(亿)': hot
      }))
    },
    
    `可抽取为公共方法,data是导出数据,name是导出的xlsx名称`
    exportHandler(data, name) {
      `将需要导出的数据转换为工作表worksheet`
      const worksheet = xlsx.utils.json_to_sheet(data)
      `创建一个新的工作簿workbook,用于存储工作表worksheet`
      const workbook = xlsx.utils.book_new()
      `将工作表worksheet添加到工作簿workbook中,并指定工作表的名称为Sheet1`
      xlsx.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
      `将工作簿workbook写入二进制数据excelBuffer,并指定生成的Excel文件类型为xlsx`
      const excelBuffer = xlsx.write(workbook, { bookType: 'xlsx', type: 'array' })
      `创建一个blob对象,用于表示Excel文件的二进制数据,type为Excel文件的MIME类型`
      const blob = new Blob([excelBuffer], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
      })
      `使用saveAs函数将Blob对象保存为文件`
      saveAs(blob, name)
    }
  }
}
</script>

以下为excel导出结果(确认过眼神,是我们需要导出的excel文件):

2. 前端将后端返回的二进制文件导出为excel

js 复制代码
1.我们需要在接口请求中使用`responseType: 'blob'`, 来获取后端返回的二进制文件

2.封装公共方法`downloadBlob`:

downloadBlob(blob, fileName) {
  `根据所提供的url地址,创建对象URL, 存储在内存中`
  const blobUrl = URL.createObjectURL(blob)
  `创建超链接标签link`
  const link = document.createElement('a')
  `将超链接标签link的跳转指向blobUrl`
  link.href = blobUrl
  `为超链接标签link下载的文件重命名`
  link.download = fileName || '下载文件'
  `触发超链接标签的点击事件,开始下载`
  link.click()
  `因为是用浏览器内存开辟的地址,所以需要及时释放对象URL,否则会一直占用系统内存,导致死机等严重影响性能的事发生`
  URL.revokeObjectURL(blobUrl)
}

3. 使用封装好的公共方法:

async exportHandler(row) {
  const res = await declareApi.matchExport({
    batchIds: [row.id]
  })
  this.downloadBlob(res, `${row.batchCode}_${row.expressCompanyName}`)
}

c. excel转换为html(主要利用xlsx.utils.sheet_to_html这个api)

js 复制代码
<template>
  <div class="app-container system-home">
    <el-upload 
      action="#" 
      :auto-upload="false" 
      accept=".xlsx,.xls" 
      :show-file-list="false" 
      :on-change="onChange"
    >
      <el-button size="small" type="primary">上传excel文件</el-button>
    </el-upload>
    <h4 class="mb10">excel展示:</h4>
    <div ref="excelRef"></div>
  </div>
</template>

<script>
import * as xlsx from 'xlsx'

export default {
  data() {
    return {
      excelData: []
    }
  },

  methods: {
    async onChange(file) {
      `两种方案皆可`
      
     `1. 非promise版`
      const reader = new FileReader()
      reader.onload = (event) => {
        let workbook = xlsx.read(event.target.result, { type: 'array', cellDates: true })
        let worksheet = workbook.Sheets[workbook.SheetNames[0]]
        this.$refs.excelRef.innerHTML = xlsx.utils.sheet_to_html(worksheet)
      }
      reader.readAsArrayBuffer(file.raw)
      
      `2. promise版(同a方向的代码)`
      let dataBinary = await new Promise((resolve) => {
        let reader = new FileReader()
        reader.readAsBinaryString(file.raw)
        reader.onload = (ev) => {
          resolve(ev.target.result)
        }
      })
      let workBook = xlsx.read(dataBinary, { type: 'binary', cellDates: true })
      let firstWorkSheet = workBook.Sheets[workBook.SheetNames[0]]
      this.$refs.excelRef.innerHTML = xlsx.utils.sheet_to_html(firstWorkSheet)
    }
  }
}
</script>

Tips: xlsx.read的文件格式,需要与FileReader读取的文件格式保持一致。

结语

往期精彩推荐(强势引流):

面试不面试,你都必须得掌握的vue知识

无论如何,你都必须得掌握的JS知识

无论如何,你都必须得掌握的JS知识(续)

我的css世界

什么?都2022年了,你还在一遍又一遍重复写form表单?

大概就这样吧。具有复杂表头的excel文件解析,会在后续抽空研究~

更多精彩文章正在快马加鞭创作中,敬请期待哦~

相关推荐
百万蹄蹄向前冲1 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5812 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路2 小时前
GeoTools 读取影像元数据
前端
ssshooter3 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友3 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry3 小时前
Jetpack Compose 中的状态
前端
dae bal4 小时前
关于RSA和AES加密
前端·vue.js
柳杉4 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化
lynn8570_blog4 小时前
低端设备加载webp ANR
前端·算法
LKAI.5 小时前
传统方式部署(RuoYi-Cloud)微服务
java·linux·前端·后端·微服务·node.js·ruoyi