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 的相关文章

  • 【vue】$bus 跨组件调用方法

    1 新建bus js import Vue from vue 使用 Event Bus const bus new Vue export default bus 2 main js引用 import bus from libs bus Vu
  • 如何计算 Ruby 数组中相同字符串元素的数量

    我有以下内容Array Jason Jason Teresa Judah Michelle Judah Judah Allison 我如何为每个生成一个计数相同的元素 Where Jason 2 Judah 3 Allison 1 Tere
  • 拓展:vue 父组件调用子组件方法ref(且父组件可通过ref调用的方法传值给子组件)

    1 ref被用来给元素或子组件注册引用信息 引用信息将会注册在父组件的 refs对象上 一 ref被用来给元素或子组件注册引用信息 引用信息将会注册在父组件的 refs对象上 div class formBtn fl 111 div div
  • vue项目日期处理day.js

    dayjs安装 1 npm 安装 npm install dayjs save 2 项目使用 import dayjs from dayjs ES 2015 dayjs format 使用介绍 1 秒 获取或设置秒 接受0到59的数字 如果
  • 根据给定索引和元素数量的列表创建子列表。序言

    我正在尝试解决一个简单的序言问题 但我无法解决它 从列表中 需要创建一个给定索引 I 的子列表 然后从 I 中创建一个给定为 N 的下一个元素 如果索引大于列表长度 我将使子列表为空 如果 N 元素数量 大于列表中的其余元素 我将获得从 I
  • HTML 元素过多会影响页面性能吗?

    我想知道两者之间是否有区别 1 10 000 个可见的表行 2 使用 display none 隐藏 10 000 个表格行 我想知道的是 如果页面上所有 10 000 行都可见 是否会导致页面滚动滞后 但如果我隐藏其中的 9000 个 这
  • 基于springboot+vue实现位置的多分馆图书馆推荐系统演示【附项目源码+论文说明】

    基于springboot实现位置的多分馆图书馆推荐系统演示 摘要 时代的变化速度实在超出人类的所料 21世纪 计算机已经发展到各行各业 各个地区 它的载体媒介 计算机 大众称之为的电脑 是一种特高速的科学仪器 比人类的脑袋要灵光无数倍 什么
  • vue的组件

    在Vue中 组件是可复用的代码块 用于构建用户界面 Vue的组件系统允许您将界面拆分为独立的 可重复使用的部件 提供了更好的代码组织和复用性 以下是在Vue中创建组件的基本步骤 创建一个组件实例 可以使用Vue extend 方法创建一个V
  • TYPO3:如何在后端添加css和JS

    我该如何添加css and javascript后端有文件吗 我想将这些文件用于自定义创建的内容元素以使它们对用户更具吸引力 System TYPO3 v9 Mode 作曲家模式 Target 自定义内容元素 在 TYPO3 v9 中 您必
  • 用于获取前一个同级的 CSS 选择器[重复]

    这个问题在这里已经有答案了 有没有办法使用纯 CSS 3 来选择具有特定类的元素的前一个同级元素 i e html div div div div div div div div css box1 some styling box2 som
  • java中同一数组的元素比较

    我正在尝试比较同一数组的元素 这意味着我想将 0 元素与其他所有元素进行比较 将 1 元素与其他所有元素进行比较 依此类推 问题是它没有按预期工作 我所做的是我有两个从 0 到 array length 1 的 for 循环 然后我有一个
  • 在 Java 中将 Element(org.w3c.dom) 转换为字符串

    我在将 Element 对象转换为 String 时遇到一个小问题 因为我需要将一个字符串传递给特定的方法 我尝试过使用 toString 或使用分配给它的字符串变量 没有一项试验是正确的 我们怎样才能轻松地进行转换 并且字符串对象还应该显
  • R:删除向量的最后一个元素

    如何删除动物园系列的最后 100 个元素 我知道名称 元素 符号 但我无法减去整个部分 我喜欢用head因为这样更容易打字 其他方法可能执行得更快 但我很懒 而我的计算机却不是 x lt head x 100 gt head 1 102 1
  • 当元素有多个类时,jquery 按特定类查找元素

    所以我正在做一些后端团队在构建时没有经过深思熟虑的事情 这给我留下了一个充满 div 的文档 我正在做的是从我需要单击的元素回滚 获取父容器 然后在父容器中找到一个元素class alert box warn class alert box
  • 如何检查可见 DOM 中是否存在元素?

    如何在不使用getElementById method 我已经设置了一个现场演示 http jsbin com apawi5 3以供参考 我还将在这里打印代码
  • 对其他元素值的 XSD 限制

    是否可以在 XSD 文档中对其他元素值进行限制 例如 我有国家和州元素 如果国家 地区等于美国 那么我需要限制指定枚举的状态元素值 否则状态可以只是固定长度的字符串 当前 XSD 的示例 始终将状态限制为枚举
  • 按位置获取元素?

    我正在研究 SVG 脚本 有 getElementById 或 getElementsByTagName 但我找不到任何方法来按位置获取元素 比如获取位置为x 10 y 10的元素 有什么办法可以实现这个目标吗 var yourElemen
  • 当我尝试从列表中删除元素时,如何忽略 ValueError?

    如果我打电话 如何忽略 不在列表中 错误消息a remove x when x不在列表中a 这是我的情况 gt gt gt a range 10 gt gt gt a 0 1 2 3 4 5 6 7 8 9 gt gt gt a remov
  • ElementTree 和 Element 有什么区别? (Python XML)

    from xml etree ElementTree import ElementTree Element SubElement dump elem Element 1 sub SubElement elem 2 tree ElementT
  • Ant Macrodef:有没有办法获取元素参数的内容?

    我正在尝试在 Ant 中调试宏定义 我似乎找不到一种方法来显示作为元素发送的参数的内容

随机推荐

  • 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