Vue 中使用 Upload 组件上传 Excel

2023-11-11

vue 中使用 Element 的 upload 组件上传 Excel,大致可以分两种情况

  1. 使用 action 上传到服务器
  2. 使用 axios 上传到服务器

注意:上传文件可能由于前后端格式不统一导致上传失败

  • application/x-www-form-urlencoded 一般情况下使用这个比较多
  • multipart/form-data
  • application/json

使用 action

使用 action 时,首先会使用OPTIONS方法发起一个预检请求,从而获知服务器是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。后端返回 204,以防处理 POST 请求时访问错误

注意:使用 action ,需要后端做跨域处理。比如 Nginx 反向代理、CORS 等

效果如下:

备注:

  1. 如果希望使用 ajax 发送请求可以配置 http-request
  2. Window 电脑可以选择 所有文件(*.*) ,之后可以上传任意文件,最好在上传之前做个 before-upload 判断类型处理

代码如下:

<template>
  <div>
    <el-upload
      ref="upload"
      :accept="fileType.join(',')"
      :limit="1"
      :headers="upload.headers"
      :action="upload.url"
      :disabled="upload.isUploading"
      :before-upload="beforeUpload"
      :on-progress="handleFileProgress"
      :on-success="handleFileSuccess"
      :auto-upload="false"
      drag
    >
      <i class="el-icon-upload" />
      <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
      <div slot="tip" class="el-upload__tip" style="color: red">
        提示:仅允许导入“xls”或“xlsx”格式文件!
      </div>
    </el-upload>
    <el-button type="success" size="mini" @click="submitUpload">上传到服务器</el-button>
  </div>
</template>

<script>
import { getToken } from '@/utils/auth'
export default {
  name: 'Upload',
  data() {
    return {
      fileType: ['.xlsx', '.xls'],
      upload: {
        // 设置上传的请求头部
        headers: { Authorization: getToken() },
        // 上传地址
        url: 'https://jsonplaceholder.typicode.com/posts/',
        // 是否更新已经存在的用户数据
        isUploading: false
      }
    }
  },
  methods: {
    // 文件上传中处理
    handleFileProgress() {
      this.upload.isUploading = true
    },
    // 文件上传成功处理
    handleFileSuccess() {
      this.upload.isUploading = false
      this.$refs.upload.clearFiles()
    },
    // 提交上传文件
    submitUpload() {
      this.$refs.upload.submit()
    },
    // 上传文件之前的钩子
    beforeUpload(file) {
      const isXlsx = file.type === 'application/vnd.ms-excel'
      if (!isXlsx) {
        this.$message.error('上传文件只能是 xlsx 或 xls 格式')
      }
      return isXlsx
    }
  }
}
</script>

不使用 action

上面需要后端配合使用,沟通起来还是比较麻烦的,还是推荐不使用 action,自己处理 ajax 请求可以更自由些

效果如下(数据是拿 mock 随机生成存入 Excel 的):

FileReader - MDN

  • 想把文件以断点续传的形式传给服务器,一般使用 readAsArrayBuffer() 读取文件
  • 想把文件中的数据展示到页面上,一般使用 readAsBinaryString() 读取文件

Element Upload

  • :on-change 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用

    第一个参数是 file,里面有文件内容、状态等信息

  • 把文件内容通过 FileReader 转换成二进制文件后

    再通过 xlsx.read 读取,即可拿到 Excel 数据内容

  • 最后通过 xlsx.utils.sheet_to_json 即可转换成我们需要的数据格式

Element Loading

  • Loading.service(options) 以服务的方式调用的 Loading 需要异步关闭

    需结合 this.$nextTick() 使用

代码如下:

<template>
  <div class="uploadBox">
    <!-- 上传文件按钮 -->
    <div class="buttonBox">
      <el-upload
        action
        accept=".xlsx,.xls"
        :show-file-list="false"
        :on-change="handleChange"
        :auto-upload="false"
      >
        <el-button slot="trigger" type="primary">选取Excel文件</el-button>
        <el-button type="success" :disabled="disabled" @click="submit">提交到服务器</el-button>
      </el-upload>
    </div>

    <!-- 解析出来的数据 -->
    <div v-show="show" class="tableBox">
      <h3>
        <i class="el-icon-info">请您检查无误后,再点击“提交到服务器”按钮</i>
      </h3>
      <el-table :data="tempData" border style="width: 100%" :height="height">
        <el-table-column prop="name" label="姓名" min-width="50%" />
        <el-table-column prop="phone" label="电话" min-width="50%" />
      </el-table>
    </div>
  </div>
</template>

<script>
import xlsx from 'xlsx'
import { Loading } from 'element-ui'
import uploadExcel from '@/api'
export default {
  name: 'Upload',
  data() {
    return {
      height: document.documentElement.clientHeight - 130,
      tempData: [],
      show: false,
      disabled: false,
      character: {
        name: {
          text: '姓名',
          type: 'string'
        },
        phone: {
          text: '电话',
          type: 'string'
        }
      }
    }
  },
  methods: {
    // 采集excel数据
    async handleChange(file) {
      const originData = file.raw
      if (!originData) return
      this.show = false
      const loadingInstance = Loading.service({
        text: '努力加载中!!!',
        background: 'rgba(0, 0, 0, 0.8)'
      })
      const binaryData = await this.readFile(originData)
      const workbook = xlsx.read(binaryData, { type: 'binary' })
      const worksheet = workbook.Sheets[workbook.SheetNames[0]]
      const data = xlsx.utils.sheet_to_json(worksheet)
      this.tempData = this.handleData(data)
      await this.delay(300)
      this.show = true
      loadingInstance.close()
    },
    // 把读取出来的数据转换为服务器需要的格式
    handleData(data) {
      const arr = []
      const char = this.character
      data.forEach(item => {
        const obj = {}
        for (const key in char) {
          if (Object.hasOwnProperty.call(char, key)) {
            const el = char[key]
            let val = item[el.text] || ''
            const type = el.type
            type === 'string' ? (val = String(val)) : null
            type === 'number' ? (val = Number(val)) : null
            obj[key] = val
          }
        }
        arr.push(obj)
      })
      return arr
    },
    // 提交数据给服务器
    async submit() {
      if (this.tempData.length <= 0) {
        this.$message({
          message: '请先选择Excel文件',
          type: 'warning',
          showClose: true
        })
        return
      }
      this.disabled = true
      const loadingInstance = Loading.service({
        text: '努力加载中!!!',
        background: 'rgba(0, 0, 0, 0.8)'
      })
      await this.delay(300)
      // 发送API请求
      uploadExcel(this.tempData).then(() => {
        this.$message({
          message: 'Excel文件已上传完毕',
          type: 'success',
          showClose: true
        })
        this.show = false
        this.disabled = false
        loadingInstance.close()
      })
    },
    readFile(file) {
      return new Promise(resolve => {
        const reader = new FileReader()
        reader.readAsBinaryString(file)
        reader.onload = e => {
          resolve(e.target.result)
        }
      })
    },
    delay(interval = 0) {
      return new Promise(resolve => {
        const timer = setTimeout(_ => {
          clearTimeout(timer)
          resolve()
        }, interval)
      })
    }
  }
}
</script>

<style scoped>
.buttonBox {
  padding: 15px;
  display: flex;
}
.el-button {
  margin-right: 20px !important;
}
.tableBox {
  padding: 0 15px;
}
h3 {
  font-size: 18px;
  color: #f56c6c;
  padding-bottom: 15px;
}
</style>

导出数据

如下方法使用 xlsx 导出,也可以使用 xlsx + file-saver 导出

  • @selection-change ,当选择项发生变化时会触发该事件

    参数为 selection,拿到后处理一下

  • 之后通过 xlsx.utils.json_to_sheet 将其变成 sheet

    再新建一个表格 xlsx.utils.book_new

    往表格插入数据 xlsx.utils.book_append_sheet

    最后通过 xlsx.writeFile 即可下载

const arr = this.selectionList.map(item => {
  return {
    编号: item.id,
    姓名: item.name,
    电话: item.phone
  }
})
const sheet = xlsx.utils.json_to_sheet(arr)
const book = xlsx.utils.book_new()
xlsx.utils.book_append_sheet(book, sheet, '表格名')
xlsx.writeFile(book, `user${new Date().getTime()}.xls`)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue 中使用 Upload 组件上传 Excel 的相关文章

  • 【AMD、CMD和CommonJS】

    CommonJS规范的特点 对于基本数据类型 属于复制 即会被模块缓存 同时 在另一个模块可以对该模块输出的变量重新赋值 对于复杂数据类型 属于浅拷贝 由于两个模块引用的对象指向同一个内存空间 因此对该模块的值做修改时会影响另一个模块 当使
  • Java异常分类总结

    在Java中 所有的异常都有一个共同的祖先Throwable 可抛出 类 Throwable指定代码中可用异常传播机制通过Java应用程序传输的任何问题的共性 Throwable有两个重要的子类 Exception 异常 和Error 错误
  • LeetCode-1792. 最大平均通过率【堆,优先队列,贪心】

    LeetCode 1792 最大平均通过率 堆 优先队列 贪心 题目描述 解题思路一 优先队列 首先任何一个班级 x y 加入一个聪明的学生之后增加的通过率为diff x 1 y 1 x y 那么对p进行堆排序 每次取最大的即可 解题思路二

随机推荐

  • Excel打开后关闭就马上跳出 Visual c++ Runtime Error R6025

    环境 Win10 专业版 Excel 2016 绿盾加密环境 问题描述 Excel打开后关闭就马上跳出 visual c runtime error R6025 runtime error program c program files m
  • KVM和QEMU

    原文地址 KVM和QEMU 作者 embeddedlwp 目录 1 硬件虚拟化技术背景 2 KVM的内部实现概述 2 1 KVM的抽象对象 2 2 KVM的vcpu 2 3 KVM的IO虚拟化 2 3 1 IO的虚拟化 2 3 2 Virt
  • jdk1.8.191 JVM内存参数 InitialRAMPercentage和MinRAMPercentage

    MaxRAMPercentage InitialRAMPercentage MinRAMPercentage 这三个参数是JDK8U191为适配Docker容器新增的几个参数 类比Xmx Xms 至于 XX InitialRAMFracti
  • 物联网安全概述

    什么是物联网 在你学习有关IPv6的时候 你的老师或许说过 有一天在你的房子每个设备都会有一个IP 物联网基本上就是处理每天的事务 并把它们连接到互联网上 一些常见的物联网设备 如灯光 窗帘 空调 也有像冰箱这样的不太常见的设备 甚至一个卫
  • [sicily] 1003. 相连的1

    声明 原题目转载自中山大学sicily平台 解答部分为原创 Problem 对于一个01矩阵A 求其中有多少片连成一片的1 每个1可以和上下左右的1相连 请为下面的Solution类实现解决这一问题的函数countConnectedOnes
  • 聚合支付行业术语,你get到了吗?

    俗话说 内行看门道外行凑热闹 每一个行业都有它独特的专业术语 对于外行人来说 这些专业术语就跟专有名词一样难懂 支付行业也是一样 因为是近几年的新兴行业 很多人对这一行不懂 甚至一些在支付行业工作的人 对这一行的很多名词概念也很模糊 认知仅
  • 基础篇(二):内存屏障是什么

    目录 前置知识 内存屏障 什么是内存屏障 作用 内存屏障的分类 1 强制读取 刷新主内存的屏障 强制刷新主内存 Load屏障 强制读取主内存 Store屏障 总结 2 禁止指令重排序的屏障 LoadLoad屏障 StoreStore屏障 L
  • 怎么修改游戏内存服务器,修改游戏服务器内存

    修改游戏服务器内存 内容精选 换一换 当您成功创建私有镜像后 镜像的状态为 正常 您可以使用该镜像创建服务器实例或云硬盘 也可以将镜像共享给其他帐号 或者复制镜像到其他区域 私有镜像的生命周期如图1所示 通过华为云创建的ECS服务器默认使用
  • mysql客户端小海豚_MySQL基础

    1 数据库概述 1 1数据的存储方式 第一种存储方式是创建对象 实际上new出来的对象不就是用来存数据的嘛 创建对象就是在堆内存中为对象请求了一个空间 相当于是将对象存入堆内存 第二种方式存文件中 这个在IO流部分我们就是这么处理的 但是缺
  • Python批量改文件名

    对以下路径中的文件名批量修改 文章目录 一 读取指定路径中的文件名 二 正则表达式提取需要保留的部分 1 介绍re库 2 re库中函数的用法 1 re findall 最常用 2 re sub pattern repl string cou
  • 数仓知识点

    传统数仓知识 1 数据仓库分层 ODS 数据准备层 该区为数据仓的准备区 直接输入源数据 如业务库 埋点日志和消息队列等 DWD 数据细节层 该层为业务层和数据层的隔离层 保持和ODS层相同的颗粒度 该层还进行了数据清洗和规范化操作 例如去
  • 阿里巴巴笔试-2020.7.27-第二题 藏宝架

    题目 有个藏宝架有n层 每层的宝物数量不一 每个宝物都有其价值 现在要求拿出m个宝物 并且需要遵守规则 每次只能拿选定层的两端的宝物 要拿出的m个宝物的总价值是各种方案里最大的 输入 第一行是 n 和 m 后面每一行是各层的数据 n m 下
  • WebSocket 基于JAVA Spring boot Spring Colud 的使用

    先上代码再看调试结果 package com qiang user util import com alibaba fastjson JSONObject import org springframework stereotype Comp
  • 软考网络工程师-最新最全小白攻略

    一 前言 最近Beau 博主本人 也是考取了2023年上半年的软考网络工程师 这里也准备给小白们做一些避坑流程 这里附上通过图 二 考前准备 1 报考条件 无 无年龄 资质 学历限制 无需通过软考初级才能报考 是中国守法公民即可报名 2 考
  • webpack 保存文件后自动打包_自动打包插件webpack-dev-server的安装、配置及使用

    1 介绍 webpack dev server插件可以实现Webpack的自动打包编译 这样 就不需要每次修改完代码都重新手动输入webpack打包了 2 安装 在项目的根路径下输入 cnpm i webpack dev server D
  • Python----模块(Module)和包(Package)

    Python 包 包 定义 为了组织好模块 会将多个模块分为包 Python 处理包也是相当方便的 简单来说 包就是文件夹 但该文件夹下必须存在 init py 文件 常见的包结构如下 最简单的情况下 只需要一个空的 init py 文件即
  • uniapp中使用网页录音并上传声音文件(发语音)——js-audio-recorder的使用【伸手党福利】

    uniapp中上传音频只能在app或小程序当中实现 如何使用网页完成语音的录制和上传则成为了困扰前端童鞋的重点 本文着重解决 js audio recorder报 error 浏览器不支持getUserMedia 的问题 js audio
  • qt使用socket连续发图片,服务端使用qt或者python接受图片

    首先客户端是用qt 不能用python这种 首先在pro里面 QT network 然后引入头文件 include
  • 2023最新AI创作商用ChatGPT源码分享+支持AI绘画

    一 SparkAI智能创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统 本期针对源码系统整体测试下来非常完美 可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统 那么如何搭建部
  • Vue 中使用 Upload 组件上传 Excel

    vue 中使用 Element 的 upload 组件上传 Excel 大致可以分两种情况 使用 action 上传到服务器 使用 axios 上传到服务器 注意 上传文件可能由于前后端格式不统一导致上传失败 application x w