vue3导入excel并解析excel数据渲染到表格中,纯前端实现。

需求

用户将已有的excel上传到系统,并将excel数据同步到页面的表格中进行二次编辑,由于excel数据不是最终数据,只是批量的一个初始模板,后端不需要存储,所以该功能由前端独立完成。

吐槽

系统中文件上传下载预览三部曲走了一遍,万万没想到还要自己实现同步数据。

实际

反手各种资料开始查阅,终于找到了可以完美实现该需求的方法,来记录下我的实现方案。希望对有需要的小伙伴有帮助。

注意以下为正文(重要内容),好好阅读,不要漏掉重要知识点奥~


涉及到的主要知识点

  • 插件xlsx
  • elementUI plus中的Upload 上传组件
  • 动态设置 ref

展开说说:

1、插件xlsx

javascript 复制代码
// 在项目根路径 安装xlsx
npm install -S xlsx

// 在需要使用的页面引入xlsx
import * as xlsx from 'xlsx'

2、upload上传组件

上传组件的自动上传方法,传参方法,详细可翻阅elementUI plus官网

3、动态设置ref

涉及到动态设置ref的原因:

一是由于upload组件在设置了 :limit="1",在上传第一个文件之后,浏览器会保存着我们已经上传的文件,导致我们继续上传文件的时候,页面没有反应;解决该问题需要在on-success钩子函数中通过ref来清除已经上传的文件。

javascript 复制代码
<template>
    <div>
        <el-upload
          ref="importExcelRef"
          :action="VITE_APP_API_URL"
          :limit="1"
          :show-file-list="false"
          class="uploadExcelContent"
          :on-success="importSuccess"    
        >
          <div title="导入excel">
            <div class="importExcel"></div>
          </div>
        </el-upload>
    </div>
</template>
<script setup>
    import { ref } from 'vue'
    const importExcelRef = ref(null)
    const importSuccess = ()=>{
       importExcelRef.value.clearFiles();
    }
</script>

二是因为表单中存在多个表格需要导入excel作为基础数据进行编辑,且表格数量不固定,是根据后端数据渲染的,所以在清空上传文件的时候,需要处理未知的多个,所以需要动态设置ref。

javascript 复制代码
<template>
    <div>
        <el-upload :ref="(el) => handleSetUploadRefMap(el, rowIndex,compIndex)">
          <div title="导入excel"  >
            <div class="importExcel"></div>
          </div>
        </el-upload>
    </div>
</template>
<script>
import { ref } from 'vue'
const uploadRefMap = ref({});
// 动态设置upload Ref
const handleSetUploadRefMap = (el,rowIndex,compIndex) => {
  if (el) {
    uploadRefMap.value[`Upload_Ref_${rowIndex}_${compIndex}`] = el
  }
}
</script>

需求实现代码

javascript 复制代码
<template>
    <div>
      <!-- 上传excel -->
      <el-upload
        :ref="(el) => handleSetUploadRefMap(el)"
        action=""
        :http-request="httpExcelRequest"
        :limit="1"
        :show-file-list="false"
        class="uploadExcelContent"
        :data={}
      >
        <div title="导入excel" style="cursor: pointer;" >
          <div>导入excel</div>
        </div>
      </el-upload>

      <!-- 列表 -->
      <div class="excel-content"  v-for="(rowItem,rowIndex) in excelList" :key="rowIndex">
        <div class="comp" v-for="(comp,compIndex) in rowItem" :key="compIndex">{{comp}}</div>
      </div>
    </div>
</template>

<script setup name="mainContent">
import * as xlsx from 'xlsx' 
import {ElMessage} from 'element-plus'
import { ref } from 'vue'
const uploadRefMap = ref({});
const excelList = ref([])

// 动态设置upload Ref
const handleSetUploadRefMap = (el) => {
  if (el) {
    uploadRefMap.value[`Upload_Ref`] = el
  }
}

// 文件上传自定义
const  httpExcelRequest = async (op) => {
  // 获取除文件之外的参数,具体根据实际业务需求来
  console.log(op.data)
  // 获取上传的excel  并解析数据
  let file = op.file
  let dataBinary = await readFile(file);
  let workBook = xlsx.read(dataBinary, { type: "binary", cellDates: true })
  let workSheet = workBook.Sheets[workBook.SheetNames[0]]
  const excelData = xlsx.utils.sheet_to_json(workSheet,{ header: 1 })
  excelList.value = excelData
  console.log(excelData)
  if(uploadRefMap.value[`Upload_Ref`]){
    uploadRefMap.value[`Upload_Ref`].clearFiles();
  }
}

const readFile = (file) => {
return new Promise((resolve) => {
  let reader = new FileReader()
  reader.readAsBinaryString(file)
  reader.onload = (ev) => {
    resolve(ev.target?.result)
  }
})
}

</script>

<style lang="scss" scoped>
.uploadExcelContent{
  display: flex;
  flex-direction: row;
}
.excel-content{
  display: flex;
  flex-direction: row;
  align-items: center;
  .comp{
    width: 200px;
    font-size: 12px;
  }
}
</style>

由于业务需求不同,对表格数据的详细处理逻辑,就不在这里显示了,可根据自己的数据结构进行赋值操作,运行demo后可以直接在控制台查看拿到的excel数据。

今天就到这里了,会继续加油的,是亮晶晶的芋头哟~

相关推荐
yinxiangzhongqing12 分钟前
loadash知识整理
前端·javascript·chrome
德莱厄斯31 分钟前
三行代码完成国际化适配,妙~啊~
前端·javascript·babel
2301_7891695434 分钟前
JSON.parse(JSON.stringify())深拷贝不会复制函数
开发语言·前端·javascript
程序员XC37 分钟前
前端性能优化的思考过程
前端·javascript·面试
皮皮虾我们跑1 小时前
web—HTML
前端·html
JosieBook1 小时前
【前端】如何在HTML中调用CSS和JavaScript(完整指南)
前端·css·html
唐诗1 小时前
这位同学来说一说 vue3 的组件通信
前端
积跬步,慕至千里1 小时前
pyspark RDD相关常用函数使用案例
前端·javascript·ajax
星星不打輰2 小时前
Vue脚手架基础
前端·javascript·vue.js