Skip to content

以前读取Excel都是通过服务器端进行读取的,那是因为大多数用户的电脑配置普遍低,读取大批量数据的Excel可能会造成页面数据卡顿。在前后端分离的时代,我们不方便准确的估算读取数据后业务的进度状态,可以通过将Excel数据进行本地读取进行分批上传,从而估算业务处理时间以进度条的形式展现给用户。

shell
npm install xlsx --save

本地读取Excel通用组件封装

我这里结合ElementPlus框架实现,并做成了通用组件的形式,您可以直接复制到项目中,当作通用组件来使用。

vue
<template>
  <el-upload class="upload" accept=".xlsx,.xls" :before-upload="upload" drag action="" :limit="1">
    <el-icon class="el-icon--upload"><upload-filled /></el-icon>
    <div class="el-upload__text">将文件拖拽到此处 <em>点击上传</em></div>
    <template #tip>
      <div class="el-upload__tip">
        .xlsx/.xls <slot></slot>
      </div>
    </template>
  </el-upload>
</template>

<script setup>
import { UploadFilled } from "@element-plus/icons-vue"
import { read, utils } from "xlsx"
import { ElMessage } from "element-plus"

const emits = defineEmits(["success"])
const props = defineProps({
  // 标题与字段对应关系
  relations: {
    type: Object,
    default: undefined,
    required: false
  }
})

const upload = (file) => {
  const fileReader = new FileReader()
  fileReader.onload = (ev) => {
    try {
      const data = ev.target.result
      const workbook = read(data, {
        type: "binary"
      })
      // 取第一张表
      const wsname = workbook.SheetNames[0]
      // 生成json表格内容
      const ws = utils.sheet_to_json(workbook.Sheets[wsname])
      if (props.relations) {
        // 将标题替换为字段
        emits("success", generateData(ws))
      } else {
        emits("success", ws)
      }
    } catch (e) {
      ElMessage.error("Excel读取失败")
      return false
    }
  }
  fileReader.readAsBinaryString(file)
  // 阻止ElUpload默认上传
  return false
}

/**
 * 筛选数据
 */
const generateData = results => {
  const arr = []
  results.forEach(item => {
    const info = {}
    Object.keys(item).forEach(key => {
      info[props.relations[key]] = item[key]
    })
    arr.push(info)
  })
  return arr
}
</script>

<style lang="scss" scoped>
.upload {
  max-width: 800px;
  margin: 0 auto;
}
</style>

使用本地读取Excel通用组件

  • relations是标题与字段对应关系,用户上传一般是使用中文标题进行区分的,但是我们向后端传递数据的字段一般是英文格式,因此需要满足其对应关系
  • @success是回调方法,读取成功后会将数据返回
vue
<template>
  <div>
    <upload-excel v-loading="loading" :relations="relations" @success="parseExcelSuccess">
      <el-button type="primary" link><a href="#">下载模板</a></el-button>
    </upload-excel>
  </div>
</template>

<script setup>
import UploadExcel from "@/components/UploadExcel/index.vue" // 存放上文通用组件的路径

const relations = {
  用户名: "username",
  密码: "password",
  昵称: "nickName",
  邮箱: "mailbox"
}

const parseExcelSuccess = async (mDataList) => {
 	console.log(mDataList) // mDataList是一个数组,就是读取的excel内容
}
</script>