Element UI的el-upload文件上传与ZIP文件解压上传

在实现文件上传功能时,有需要支持多种文件格式并处理的特殊需求。本文将分享如何使用Element UI的el-upload组件实现支持普通文件和ZIP文件解压的混合上传方案。

技术方案核心

  • 上传组件:Element UI的el-upload组件作为基础
  • 文件解压:JSZip处理ZIP文件内容
  • 编码处理:iconv-lite解决中文文件名乱码问题
  • 混合上传:
    1. 普通文件:使用el-upload原生提交
    2. 解压文件:通过axios单独上传
核心实现代码
js 复制代码
import JSZip from 'jszip'
import axios from 'axios'

data() {
    return {
      uploadUrl: '', 
      accept: '.zip,.doc,.docx,.txt,.pdf,.xls,.xlsx,.jpeg,.jpg,.png',
      uploadHeaders: { Authorization: 'Bearer ' + getToken() },
      uploadedFiles: [], 
      fileList: [], 
    }
  },

在on-change事件中解压zip文件。解压成功,清除zip文件,将解压的文件放入el-upload的fileList中;解压失败,过滤掉zip文件。

js 复制代码
async handleFileChange(file, fileList) {
      this.fileList = fileList // 更新文件列表
      this.hasFiles = fileList.length > 0 // 更新文件标志
      if (file.name.toLowerCase().endsWith('.zip') && this.zipFg) {
        try {
          const zip = new JSZip()
          const content = await file.raw.arrayBuffer()
          let iconv = require('iconv-lite')

          const zipContent = await zip.loadAsync(content, {
            decodeFileName: function (bytes) {
              return iconv.decode(bytes, 'gbk')
            }
          })
          const pdfFiles = []
          await Promise.all(
            Object.values(zipContent.files).map(async (entry) => {
              if (!entry.dir) {
                const blob = await entry.async('blob') // 使用 await 等待 blob 获取完成
                pdfFiles.push({
                  name: entry.name,
                  blob,
                  status: 'success',
                  percentage: 0,
                  extracted: true, 
                })
              }
            })
          )
          const nonZipFiles = fileList.filter((f) => !f.name.toLowerCase().endsWith('.zip'))
          this.fileList = [...nonZipFiles, ...pdfFiles]
        } catch (err) {
          const nonZipFiles = fileList.filter((f) => !f.name.toLowerCase().endsWith('.zip'))
          this.fileList = [...nonZipFiles]
          this.$message.error('解压失败')
        }
      }
    },

使用axios上传解压后的文件

js 复制代码
async uploadPdfFiles(pdfFiles) {
      for (const pdfFile of pdfFiles) {
        const formData = new FormData()

        formData.append('file', pdfFile.blob, pdfFile.name)
        try {
          const response = await axios.post(this.uploadUrl, formData, {
            headers: {
              ...this.uploadHeaders, // 使用上传请求头
              'Content-Type': 'multipart/form-data',
            },
          })
          this.uploadedFiles.push({
            fileName: response.data.data.name,
            url: response.data.data.url,
            status: 'success',
          })
        } catch (error) {
          this.$message.error(`上传文件 ${pdfFile.name} 失败`)
        }
      }
    },

文件上传与上传成功后的处理

js 复制代码
  /**
     * 开始上传文件
     */
    async startUpload() {
      // 校验是否有文件
      if (!this.hasFiles) {
        this.$message.warning('请先选择文件后再上传!')
        return
      }

      // 这里可设置上传状态

      // 分离解压文件和普通文件
      const normalFiles = this.fileList.filter((f) => !f.extracted)
      const extractedFiles = this.fileList.filter((f) => f.extracted)

      // 1. 上传普通文件
      if (normalFiles.length > 0) {
        this.$refs.upload.submit()
        return
      }
      // 2. 上传解压文件
      if (extractedFiles.length > 0) {
        await this.uploadPdfFiles(extractedFiles)
        if(this.uploadedFiles.length === 0) {
          return
        }
       this.$message.success(`文件上传成功.`)
          setTimeout(() => {
            this.uploadSuccess()
          }, 500)
      }
    },

    async handleUploadSuccess(res, file, fileList) {
      if (res.code === 200) {
        this.uploadedFiles.push({
          fileName: file.name,
          url: res.data.url,
          status: file.status,
        })
        let files = this.fileList.filter((f) => !f.blob)
        if (files.every((f) => f.status === 'success')) {
          const extractedFiles = this.fileList.filter((f) => f.extracted)
          if (extractedFiles.length > 0) {
            await this.uploadPdfFiles(extractedFiles)
            if(this.uploadedFiles.length === 0) {
              return
            }
          }
          this.$message.success(`文件上传成功.`)
          setTimeout(() => {
            this.uploadSuccess()
          }, 500)
        }
      } else {
        this.$message.error(`文件 ${file.name} 上传失败.`)
      }
    },

    // 上传成功后的处理,包含重置以及通知父组件等
    uploadSuccess() {
      this.uploadedFiles.forEach(item => {
        delete item.status
      });
      this.$emit('uploadedFiles', this.uploadedFiles)
      this.uploadedFiles = []
      this.fileList = []
    },

有更好建议或发现错误,欢迎指正!

相关推荐
Dream-Y.ocean18 小时前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Highcharts.js19 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
kyriewen1 天前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
工控丫丫1 天前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
Dream-Y.ocean1 天前
鸿蒙PC平台星图遥感适配实战:基于 Electron 壳方案的纯 JavaScript 遥感图像处理引擎开发
javascript·electron·harmonyos
螺丝钉tina1 天前
[Playwright ][16]Playwright + TypeScript API 自动化测试实战:API测试
前端·javascript·typescript
Highcharts.js1 天前
React 中原生支持使用 JSX 组件配置自定义表格 Highcharts Grid
前端·javascript·react.js·前端框架·jsx·highcharts·自定义表格
Java后端的Ai之路1 天前
【AIAgent开发】-Agent工具封装成CLI(纯干货!!!)
java·javascript·人工智能·agent·cli
薛定谔的猫-菜鸟程序员1 天前
Electron开发超详细教程(从入门到放弃)
前端·javascript·electron