场景

需要:

  • 下载一个固定模板excel
  • 上传一个excel,并解析其内容

参考:前端导出Excel【支持样式配置,多sheet,多级表头】在我们的管理系统项目中,将表格数据导出为Excel文件是很常见 - 掘金

依赖

exceljs file-saver

exceljs - npm — exceljs - npm
file-saver - npm

下载

封装一个下载的方法。

import ExcelJS from 'exceljs'
// @ts-ignore
import saveAs from 'file-saver'
export const exportExcel = (header: string[], data: number[][]) => {
  // 创建excel工作簿
  const workbook = new ExcelJS.Workbook()
  const worksheet = workbook.addWorksheet('Sheet1')

  // 表头
  worksheet.addRow(header)

  // 数据
  data.forEach((item) => {
    worksheet.addRow(item)
  })

  // 生成二进制数据导出
  workbook.xlsx.writeBuffer().then((buffer) => {
    const blob = new Blob([buffer], { type: 'application/octet-stream' })
    saveAs(blob, '模板.xlsx')
  })
}

调用:

const handleDownloadTempExcel = () => {
  const headers = ['序号', '测试剧-章节ID', '对照剧-章节ID']
  const datas = [
    [0, 75912, 75848],
    [1, 75913, 75849],
    [2, 75914, 75850],
    [3, 75915, 75851],
    [4, 75916, 75852],
  ]
  exportExcel(headers, datas)
}

效果:

在这里插入图片描述

上传并解析

上传使用原生的控件。点击按钮,模拟原生控件input 的点击。让input控件隐藏。

        <input
          ref="uploadExcel"
          hidden
          type="file"
          accept=".xlsx,.xls,.csv"
          @change="handleUploadChapter"
        />

        <el-button
          style="margin-left: 8px"
          type="success"
          @click="handleClickUpload"
          >上传
        </el-button>
const handleClickUpload = () => {
  uploadExcel.value?.click()
}

在这里写上传文件的方法:

const handleUploadChapter = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const files = target.files
  if (!files) {
    return
  }
  uploadFile.value = files[0]

  const list = await excelToList(uploadFile.value)
  // ....
}

将解析excel封装成一个方法:把excel解析成数组。

在这里插入图片描述

export const excelToList = async (file: File) => {
  const workbook = new ExcelJS.Workbook()
  await workbook.xlsx.read(file.stream())
  const sheet = workbook.worksheets[0]
  const excelData: string[][] = []
  sheet.eachRow((row) => {
    const list: string[] = []
    row.eachCell((cell) => {
      list.push(cell.value?.toString() || '')
    })
    excelData.push(list)
  })

  return excelData
}

上述代码在部分场景会有问题:当出现某个单元格为空时,会跳过。如:
在这里插入图片描述
会解析成:
在这里插入图片描述

这样数据就有缺失。需要:记录第一行的长度

export const excelToList = async (file: File) => {
  const workbook = new ExcelJS.Workbook()
  await workbook.xlsx.read(file.stream())
  const sheet = workbook.worksheets[0]
  const excelData: string[][] = []

  // 列数
  const firstRow = sheet.getRow(1)
  const colCount = firstRow?.cellCount || 0

  sheet.eachRow((row) => {
    const list: string[] = []
    // 确保空单元格也处理
    for (let i = 1; i <= colCount; i++) {
      const cell = row.getCell(i)
      list.push(cell.value?.toString() || '')
    }
    excelData.push(list)
  })

  return excelData
}

更多推荐