一、需求描述:在页面点击按钮弹出选择电脑文件界面可以一次选择多个文件一起上传服务器上,并把上传成功的文件展示页面上。

·

二、问题阐述:elupload支持多文件上传的,但是是同步进行的,你点击上传按钮选择多个文件后点击确定,会同时调用上传文件的接口,这样很容易导致服务器奔溃,导致接口报错

·

三、解决方法:为了解决这一难题,本文采用递归方法实现精准上传文件。

·

四、实现思路:递归上传是指:你选择了n个文件点击确定后,第一个接口上传成功或者失败后,再调用第二个接口上传第二个文件,依次等待上传完所有文件,这样做法可以大大减轻服务器的压力,就是上传时间比较长。上传效果请看下方动态示例

 主要逻辑详解

1、首先需要取消组件自动上传操作属性autoupload的值设置false,就禁用了文件的自动上传功能了,自动转化为手动,之所以选择多个文件会并行调用上传接口,就是这个属性导致的。

·

2、属性autoupload设置false之后,action属性失效了,只会触发change事件、上传失败onerror事件以及上传个数限制beforeupload事件

·

3、关键点就在于change事件选择多少个文件,这个事件就会执行多少次,例如选择了100个文件,change事件就会循环执行100次,为了保证上传的准确性,这里手写防抖事件通过防抖可以清楚的知道,上传进度到哪了,change事件什么时候结束,在这里就可以开始调用后端给我们的上传接口了。

·

4.因为我是想减少服务器压力,既在上一个文件上传结束后,再去上传下一个文件。故,我采用了递归一次传一个(递归逻辑submitUpload2事件里)。同样的,如果你想只调用一次接口,将1000个文件传给后端,那么你就将submitUpload2递归事件给修改调,改成调一次接口,传所有file文件数组即可(具体看你们后端的数据结构)。
·
5.因为是上传多个文件,时间肯定长,如果你不想继续传递后续文件,就调用submitAbort即可。但是element文档说的abort()取消上传事件不生效。所以我是直接将上传列表给置空了,所以递归也就结束了就不传递了。
.
6.同样因为上传时间长,我就设置进度条当前已上传的个数/所有需要上传个数)。但是你如果切换到其他页面的话,再切换当前上传vue页面,因为生命周期原因导致看不到上传进度。所以可以将这个上传vue页面使用keepalive进行路由缓存这样除了刷新浏览器外,切换当前还是会读缓存看到上传进度(如果你既想要缓存进度条,又想要刷新页面list等某些数据,那么你缓存页面然后activated单独调获取list数据方法即可)。
.

7.因为我的需要是,选择文件成功后,默认去上传,所以我是在防抖事件后就去调递归上传了。正常情况下,其实需要点击这个按钮然后去上传的,既手动点击上传(被注释掉了)<!– <elbutton style=”marginleft: 10px;” size=”smalltype=”success” @click=”submitUpload2″>手动点击上传</el-button> –>

以下代码仅供参考,可以直接复制使用(注意将axios的接口转化为后端提供的接口即可)!

<template&gt;
  <div class="group_insurance_order1" style="padding-top:100px;"&gt;
    <!--
      :auto-upload="false" 是否选取文件后立即进行上传 false阻止自动上传 -- 且上传前和上传成功的事件都不会再触发 只会触发@change事件了
      :http-request="uploadFile"  覆盖默认的上传行为,可以自定义上传的实现(this.$refs.upload1.submit()  会触发调用uploadFile函数)
    --&gt;
    <el-upload ref="upload1" class="upload-demo" action="/chc-shop/api/v1/accident/szcp/electronicfile/upload" accept=".pdf" :disabled="disabledUpload" :auto-upload="false" :on-change="changeFile" :on-error='fileErr' :on-exceed="handleExceed" :file-list="fileList1" :before-upload="beforeAvatarUpload" :on-success="msgSuccessOne" :data="fileData" list-type="picture" drag :show-file-list="false" :multiple="true" :limit="1000">
      <i class="el-icon-upload"></i>
      <div class="el-upload__text" style="margin-top: -10px;line-height: 20px;">
        将文件拖到此处,<em v-if="!disabledUpload">或点击上传(单个文件需小于100M,一次最多上传1000个pdf文件)</em><em v-else>(文件正在上传中,请等待...)</em>
      </div>
    </el-upload>

    <div>
      <!-- <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload2">手动点击上传</el-button> -->
      <el-button v-if="showPercent" style="margin-left: 10px;" size="small" type="success" @click="submitAbort">取消后续文件上传</el-button>
    </div>

    <div style="color:orange;" v-if="showPercent">上传过程请勿刷新浏览器跳转其他页面...</div>
    <!-- 进度条 -->
    <el-progress v-if="showPercent" :percentage="Number((percentNow*100/percentTotal).toFixed(0))"></el-progress>

  </div>
</template>

<script>
import axios from 'axios'
export default {
  data () {
    return {
      fileNum: '',  // 单词递归上传的文件
      upFileList: '',//需要依次上传的待传列表
      percentTotal: 0,//总上传个数
      percentNow: 0,//当前上传个数
      showDesc: '',//结束文案
      showPercent: false,//显示上传进度条
      time: null,// change事件是否结束 是否可以直接调手动上传事件(目前设置1.5s)
      disabledUpload: false,//正在上传中 禁止再次选择文件上传

      fileData: {
      },//上传参数

      fileList1: [],

    }
  },
  activated: {
    // 对于每次进入页面想要刷新数据,放在这里调用即可 例如 this.getList()
  },
  methods: {
    // 超出限制个数提示
    handleExceed (files, fileList) {
      console.log('当前限制一次性最多上传1000个文件', files, fileList)
      this.$message.warning("当前限制一次性最多上传1000个文件")
    },
    changeFile (file, fileList) {
      this.disabledUpload = true

      console.log('changeFile', file, fileList)
      const isLt2M = file.size / 1024 / 1024 < 100
      if (!isLt2M) {
        this.$message.warning('上传文件大小不能超过 100M')
        // return false // 这个return无效去掉
      }

      if (!(file.name.indexOf('.pdf') > -1)) {
        this.$message.warning("当前仅支持pdf格式的文件上传")
        // return false // 这个return无效去掉
      }


      // 符合条件进入待传列表
      this.upFileList = []
      for (let x of fileList) {
        if (x.raw &amp;&amp; (x.name.indexOf('.pdf') > -1) &amp;&amp; (x.size / 1024 / 1024 < 100)) {// 过滤掉非pdf 和小于100M的
          this.upFileList.push(x.raw)
          this.percentTotal = this.upFileList.length
          this.percentNow = 0
          this.showPercent = false
          this.showDesc = ''
        }
      }

      clearTimeout(this.time)
      this.time = setTimeout(() => {
        this.time = null
        console.log('防抖 高频触发后n秒内只会执行一次  再次触发重新计时')
        this.fnBegin()//说明此时change了所有文件了 可以上传了
      }, 1500)

    },
    fnBegin () {
      console.log('此时change了所有文件 开始上传', this.upFileList)
      this.submitUpload2()
    },
    // 正式上传掉后端接口
    submitUpload2 () {
      if (this.upFileList.length > 0) {
        this.showPercent = true

        this.fileNum = new FormData()  // new formData对象
        this.fileNum.append('file', this.upFileList[0])  // append增加数据
        this.fileNum.append('name', this.upFileList[0].name)  // append增加数据

        let _vm = this
        axios({
          url: '/chc-shop/api/v1/accident/szcp/electronicfile/upload',
          headers: {
            "Content-Type": "multipart/form-data",
          },
          method: "post",
          data: this.fileNum,
        })
          .then(res2 => {
            // 每次上传当前一个后 不论成功失败删除当前这个--如果上传失败想继续传当前这个 就把这两行注释掉
            this.percentNow = this.percentNow + 1
            this.upFileList.shift()


            console.log('上传返回', res2)
            if (res2.data.success) {
              // this.$message({
              //   message: "上传成功",
              //   type: 'success'
              // })

              // 进行递归 上传下一个
              this.submitUpload2()

            } else {
              _vm.$message({
                message: res2.data.return_message || '上传失败',
                type: "error",
              })

              // 进行递归 上传下一个
              this.showDesc = '上传结束部分文件上传失败'
              this.submitUpload2()
            }
          })
          .catch(error => {
            console.log(error)
            _vm.$message({
              message: error || '上传失败',
              type: "error",
            })

            // 每次上传当前一个后 不论成功失败就删除当前这个--如果上传失败想继续传当前这个 就把这两行注释掉
            this.percentNow = this.percentNow + 1
            this.upFileList.shift()

            // 进行递归 上传下一个
            this.showDesc = '上传结束部分文件上传失败'
            this.submitUpload2()
          })

      } else {
        this.disabledUpload = false
        this.showPercent = false
        this.upFileList = [] //清空待传列表

        this.$refs.upload1.clearFiles()
        this.fileList1 = []

        if ((this.percentNow == this.percentTotal) && this.percentTotal) {
          this.$message.success(this.showDesc ? this.showDesc : '已全部上传成功!')
          this.percentTotal = 0
          this.percentNow = 0
          this.showDesc = ''

        } else if ((this.percentNow == this.percentTotal) && this.percentTotal == 0) {
          this.$message.warning('请先选择文件!')
          this.percentTotal = 0
          this.percentNow = 0
        } else {
          this.$message.success('已部分上传成功,且取消后续文件上传!')
          this.percentTotal = 0
          this.percentNow = 0

        }

        return false
      }

    },
    // 终止后需上传
    submitAbort () {
      this.showPercent = false
      // .abort()不生效,故自己直接将this.upFileList置空 那么就不会走到递归了 就制止后续的上传了
      this.upFileList = []


      // this.upFileList.forEach(ele => {
      //   this.$refs.upload1.abort(ele)
      // })
      // this.$refs.upload1.abort()
      // this.$message.warning('已取消后续文件上传!')
    },
    fileErr (err, file, fileList) {
      this.$message({
        message: file.name + '上传失败',
        type: "error",
      })
    },



	// 这两个事件不会再触发--因为阻止了自动上传
    beforeAvatarUpload (file) {
      console.log('上传文件前', file)
    },
    msgSuccessOne (data, file, fileList) {
      console.log('成功', file)
    },


  },
};
</script>

原文地址:https://blog.csdn.net/u011313034/article/details/129065476

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_30008.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注