Excel

注意:这里是前端使用xlsx插件,将前端上传的.xls、.xlsx文件,解析得到原始列表数据
我的是vue3项目


1.安装依赖

 pnpm add xlsx@0.18.5

2.组件封装

src/components/MyExcelData/index.vue

<template>
  <div v-loading="loading">

    <div class="drop-area" @dragenter="highlight" @dragover="highlight" @dragleave="unHighlight" @drop="handleDrop"
      @click="handleClick">
      <el-icon :size="67" color="#9ea1a9" class="el-icon--upload"><upload-filled /></el-icon>
      <div class="desc" v-if="props.msg">{{ props.msg }}</div>
      <input type="file" ref="fileInput" @change="handleFiles" :multiple="multipleFlag" accept=".xlsx, .xls"
        style="display: none;">
    </div>

  </div>
</template>

<script setup>
import { defineProps } from 'vue'
import { UploadFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

import { ref } from 'vue';
import * as XLSX from 'xlsx';

defineOptions({
  name: "MyExcelData"
})
const props = defineProps({
  headerList: { type: Array, default: () => [] }, // 表头英文列表
  msg: { type: String, default: () => '' }, // 描述
})
const emit = defineEmits(["setExcelData"])

let loading = ref(false)
const tableData = ref([]);
const tableHeader = ref([]);



// const fileList = ref([]) // 当前组件内的文件集合
const inputList = ref([]) // 这个是input拿到的list 不一定调用上传接口
const fileInput = ref(null); // 上传ref
const multipleFlag = ref(false) // 是否多选

const highlight = (e) => {
  e.preventDefault();
  e.stopPropagation();
  e.target.classList.add('hover');
};

const unHighlight = (e) => {
  e.target.classList.remove('hover');
};

// 拖拽
const handleDrop = (e) => {
  e.preventDefault();
  e.stopPropagation();
  unHighlight(e);
  const files = e.dataTransfer.files;
  inputList.value = [] // 必须这几步都置空 不然无效
  for (let i = 0; i < files.length; i++) {
    inputList.value.push({
      ...files[i],
      name: files[i].name,
      size: files[i].size,
      type: files[i].type
    });
  }
  uploadFile();
};

// 点击
const handleClick = () => {
  // console.log(fileInput.value);
  fileInput.value.click(); // 使用 ref 的 value 直接访问 DOM 元素
};

// 获取点击文件
const handleFiles = (e) => {
  const files = e.target.files || e;
  // console.log('files', files, typeof files, files[0]);
  inputList.value = [] // 必须这几步都置空 不然无效
  for (let i = 0; i < files.length; i++) {
    inputList.value.push({
      file: files[i],
      name: files[i].name,
      size: files[i].size,
      type: files[i].type
    });
  }
  uploadFile();
};

// 上传文件
const uploadFile = () => {
  // console.log('inputList', inputList.value);
  const file = inputList.value[0].file
  // console.log('上传接口的文件', file);
  handleFileUpload(file)
};

const handleFileUpload = (event) => {
  loading.value = true
  tableData.value = [];
  tableHeader.value = [];

  // const file = event.target.files[0];
  const file = event
  const reader = new FileReader();
  reader.onload = (e) => {
    const data = new Uint8Array(e.target.result);
    const workbook = XLSX.read(data, { type: 'array' });
    const sheetName = workbook.SheetNames[0];
    const sheet = workbook.Sheets[sheetName];
    const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 });
    // console.log('jsonData', jsonData);
    tableHeader.value = props.headerList.length ? props.headerList : jsonData[0]
    //tableData.value  = jsonData.slice(1);

    // 遍历总数居中除第一项的每个数组
    for (let i = 1; i < jsonData.length; i++) {
      let obj = {};
      // 遍历arr1第一项的数组,将其元素作为key,与当前遍历的数组对应位置的元素作为value,构建对象
      for (let j = 0; j < tableHeader.value.length; j++) {
        obj[tableHeader.value[j]] = jsonData[i][j];
      }
      tableData.value.push(obj); // 将构建好的对象添加到arr2中
    }
    // console.log('tableData.value', tableData.value);
    // 过滤掉属性值全是undefined的对象
    function removeItemsWithUndefinedValues(arr) {
      return arr.filter(obj => {
        return Object.values(obj).some(value => value !== undefined);
      });
    }
    tableData.value = removeItemsWithUndefinedValues(tableData.value)
    // console.log(tableData.value)
    emit('setExcelData', { tableHeader: tableHeader.value, tableData: tableData.value })
    ElMessage.success('解析成功')
    loading.value = false
  };
  reader.onerror = (e) => {
    ElMessage.error('解析失败', e)
    emit('setExcelData', { tableHeader: tableHeader.value, tableData: [] })
    loading.value = false; // 可以在这里取消加载状态或者进行其他错误处理操作
  };
  reader.readAsArrayBuffer(file);

  // return 掉 不调用接口的报错
  return false
};


</script>
<style lang="scss" scoped>
.drop-area {
  width: 440px;
  height: 185px;
  border: 1px dashed #dcdfe6;
  border-radius: 6px;
  text-align: center;
  cursor: pointer;
  padding-top: 40px;
}

.drop-area:hover {
  border-color: #11716f;
}
</style>

3.子组件使用

注意点:
headerList就是列表数据的表头;一定要保证headerList的长度和数据列对应

<!-- 导入组件 -->
<MyExcelData :headerList="['tableName', 'tableType', 'tableAuthority', 'tableNameDesc']"
  @setExcelData="setExcelData" :msg="'仅支持导入表格格式,扩展名.xls、.xlsx,导入成功后,表信息将全部更新,请核对导入数据'"></MyExcelData>




// 解析数据
const setExcelData = (val) => {
  console.log('解析数据', val)
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值