• vue-simple-uploader实现多文件/文件夹以及可拖拽上传



    vue-simple-uploader是基于simple-uploader.js的vue上传组件

    1. 支持多文件/文件夹上传,拖拽上传
    2. 可暂停、继续上传
    3. 上传错误处理
    4. 支持“秒传”,通过文件判断服务端是否已存在从而实现“秒传”
    5. 支持进度、预估剩余时间、出错自动重试、重传等操作

    这里有参考文档事例

    1.效果图展示

    后面有使用拖拽上传文件/文件夹

    在这里插入图片描述
    上传遇到同名的文件会有一个弹框提示,并有相关的操作
    在这里插入图片描述

    2.安装

    npm install vue-simple-uploader --save
    

    3.vue2使用(vue3使用会报错)

    import uploader from 'vue-simple-uploader'
    //已经创建Vue实例了
    Vue.use(uploader)
    

    4.代码

    这里我只贴主要的内容,代码也都给有注释哦

     <uploader
        ref="uploader"
        :options="options"
        :auto-start="false"
        :file-status-text="fileStatusText"
        class="uploader-example"
        @file-added="onFileAdded"
        @files-added="onFilesAdded"
        @file-error="onFileError"
        @file-complete="onFileComplete"
      >
        <uploader-unsupport /> //不支持上传时显示内容
        //这个组件也有两个上传的按钮 但是我这边给隐藏了 自定义了下拉框 点击的时候 获取对应的实例 然后触发点击事件
        <uploader-btn
          id="uploader_btn"
          ref="uploadBtn"
        >选择文件</uploader-btn>
        <uploader-btn
          id="uploader_btn"
          ref="uploadFolderBtn"
          :directory="true"
        >选择文件夹</uploader-btn>
        //可拖拽的区域
        <uploader-drop class="drop">
        	//我把这个table区域变成可拖拽的了 具体看自己写的内容吧
        	<el-table></el-table>
        </uploader-drop>
        //这是上传文件显示的上传弹框,在右下角 有文件上传时显示 默认是隐藏
        <div
          v-show="isShowDropUploadFileLists"
          class="drog_list"
        >
          <uploader-list>
            <div
              slot-scope="props"
              class="file-panel"
              :class="{ collapse: collapse }"
            >
              <div class="file-title">
                <div class="title">文件列表</div>
                <div class="operate">
                  <el-button
                    type="text"
                    :title="collapse ? '展开' : '折叠'"
                    @click="collapse = !collapse"
                  >
                    <i :class="collapse ? 'el-icon-full-screen' : 'el-icon-minus'" />
                  </el-button>
                  <el-button
                    type="text"
                    title="关闭"
                    @click="CloseFilesUploadList"
                  >
                    <i class="el-icon-close" />
                  </el-button>
                </div>
              </div>
              <ul class="file-list">
                <li
                  v-for="file in props.fileList"
                  :key="file.id"
                  class="file-item"
                  :class="`file-${file.id}`"
                >
                  <uploader-file
                    ref="files"
                    :class="'file_' + file.id"
                    :file="file"
                    :list="true"
                  />
                </li>
                <div
                  v-if="!props.fileList.length"
                  class="no-file"
                >
                  <i class="iconfont icon-empty-file" /> 暂无待上传文件
                </div>
              </ul>
            </div>
          </uploader-list>
        </div>
      </uploader>
    

    相关js我是单独拎出来了然后通过mixins混入到当前vue文件了

    import { GetBatchFilesId, GetDocumentSameNameInfo } from "@/api/file"; //批量上传获取ID,对比上传文件是否跟已存在的同名的两个接口
    import { CreateFilePath, CreateFileName } from "@/utils/handleFile";//这个是入参对文件/文件夹路径和名字的处理
    export default {
      data () {
        return {
          options: {
            target: "http://test.hhh.com.cn/api/Files",//上传地址,如果有文件上传地址不同时 可以是个函数来改变
            testChunks: false,//测试每个块是否在服务端已经上传了
            allowDuplicateUploads: true, // 一个文件以及上传过了是否还允许再次上传
            query: (file, chunk) => { //上传时所带的参数 可以是个函数在选择文件时 自定义(拿到的两个参数分别是Uploader.File 实例、当前块 Uploader.Chunk 以及是否是测试模式)
              return {
                ...file.params,
                isUseLastVersionFieldValueWhenUpdate: false, // 請帶false
                path: CreateFilePath(file.relativePath, true),
                autoIdNamingType: "Auto", // 自动编码
                directoryId: 14, // 项目ID
              };
            },
          },
          fileStatusText: {//显示的状态
            success: "上传成功",
            error: "上传失败",
            uploading: "上传中",
            paused: "已暂停",
            waiting: "等待上传",
          },
        }
      },
      
     computed: {
        // 获取上传文件实例
        uploaderRef() {
          return this.$refs.uploader.uploader;
        },
     },
     
      methods: {
      //值得注意的是我这个方法是@files-added="onFilesAdded",是对当前一次性上传的所有文件做的处理,比如说上传5个文件 那就是会获得一个数组里面包括5个文件,这个函数是在file-added全部执行完后走一次
     // @file-added="onFileAdded"获取到的单个当前上传文件,按照上传顺序来的,比如说上传5个文件,那这个函数会执行5次
        // 全部文件处理 
        onFilesAdded (files, filelist) {
          this.nowUploadFiles = [...files]//当前上传的文件列表保存了一下 后面有同名弹框操作后 方便继续上传文件 不然触发到同名文件弹框了 后续的操作获取不到已经上传到一半的文件了
          let getBatchIds = ''
          const filesLength = files.length
          // 调用文件同名验证接口,这边入参用的都formData格式
          var formdata = new FormData();
          formdata.append("id", 3);
          formdata.append("directoryId", 6);
          formdata.append("isReserveDirStructure", true);
          this.fileList.forEach((v) => {
            formdata.append("paths[]", v);
          });
          this.fileNameList.forEach((v) => {
            formdata.append("filenames[]", v);
          });
          this.fileList = []
          this.fileNameList = []
          const getSameFileInfo = new Promise((resolve, reject) => {
            formdata.append("autoIdNamingType", "Auto");
            GetDocumentSameNameInfo(formdata).then(_res => {
              resolve(_res)
            }).catch(err => reject(err))
          })
          if (filesLength > 1) { //多文件或者文件夹上传的时候 入参需要带个批量ID 看自己需求哈
            // 批量上传文件
            getBatchIds = new Promise((resolve, reject) => {
              formdata.append("isTemp", false);
              GetBatchFilesId(formdata).then(_res => {
                resolve(_res)
              }).catch(err => reject(err))
            })
          }
          Promise.all([getSameFileInfo, getBatchIds]).then(res => {
            if (res && res.length) {
              // 同名文件对比弹框弹出
              this.isShowSameFiledialog = !!(res[0] && res[0].length)
              this.isShowSameFileInfo = res[0] // 同名文件列表
              // 保存批量文件ID
              this.BatchUploadId = res[1].BatchUploadId || ''
              if (!this.isShowSameFiledialog) {
                // 单个文件无同名时直接上传,不显示弹框
                console.log(files[0].name)
                files.forEach(item => {
                  item.params = {
                    sameNameUpdateisTrue: this.sameNameUpdateisTrue, // 遇到同名檔案是否更版
                    isReserveDirStructure: false,
                  }
                  item.resume();
                })
                // 显示上传文件弹框
                this.isShowDropUploadFileLists = true
                console.log('单个文件无同名时直接上传,不显示弹框')
              }
            }
          }).catch(err => console.log(err, '哈哈哈'))
        },
    
        // 文件上传获取单个文件
        onFileAdded (file, fileList) {
          const _dataPath = file.relativePath;
          // 获取到文件的路径数组和对应的文件名数组
          this.fileList.push(CreateFilePath(_dataPath, this.isFromDragDrop));
          this.fileNameList.push(CreateFileName(_dataPath));
        },
    
        // 根文件上传成功
        onFileComplete (rootFile) {
          this.$message({
            message: "上传成功!",
            type: "success",
          });
        },
    
        // 文件上传失败
        onFileError (file) {
          this.$message({
            message: "上传失败,请重试!",
            type: "error",
          });
        },
    
        // 点击关闭按钮
        CloseFilesUploadList () {
          this.uploaderRef.cancel();
          this.isShowDropUploadFileLists = false;
        },
    
      }
    }
    
    
    

    遇到同名文件弹框的操作

      <SameFileInfo
          ref="sameFileDailog"
          :isshow="isShowSameFiledialog" //显示弹框
          :same-file-info="isShowSameFileInfo"//同名文件数据列表
          @handelUpdateFile="handelUpdateSameNameFile"
       />
     // 同名文件弹框操作
        handelUpdateSameNameFile(type) {
          if (type === "cancel") { //取消操作
            this.nowUploadFiles &&
              this.nowUploadFiles.forEach((item) => {
                item.ignored = true; 
              });
            this.uploaderRef.cancel(); //关闭上传 uploaderRef是组件uploader的实例
            this.isShowDropUploadFileLists = false; //关闭上传文件列表
            // 关闭弹框
            this.isShowSameFiledialog = false;
            return false;
          }
          if (type === "skip") {//跳过
            // 点击跳过
            this.sameNameUpdateisTrue = false;
            // 过滤掉重名的文件
            const _this = this;
            _this.nowUploadFiles &&
              _this.nowUploadFiles.forEach((v) => {
                _this.isShowSameFileInfo.forEach((val) => {
                  if (val.DocumentName.split(".")[0] === v.name.split(".")[0]) {
                    v.ignored = true; //给当前上传的文件列表中同名文件都加一个属性,后续过滤掉同名文件不上传
                  }
                });
              });
          } else if (type === "replace") {
            this.sameNameUpdateisTrue = true;
          } else if (type === "add") {
            this.sameNameUpdateisTrue = false;
          }
          // 给上传插件赋值(传参)
          this.nowUploadFiles &&
            this.nowUploadFiles.forEach((item) => {
              item.params = {
                sameNameUpdateisTrue: this.sameNameUpdateisTrue, // 遇到同名檔案是否更版
                isReserveDirStructure: true, // 是否保留本地文件夾結構 (單檔可帶false)
                batchUploadId: this.BatchUploadId,
              };
              if (item.ignored) {
                this.uploaderRef.removeFile(item); //如果有同名过滤属性的则选择不上传
              }
              item.resume();
            });
          // 关闭弹框
          this.isShowSameFiledialog = false;
          // 显示上传文件弹框
          this.isShowDropUploadFileLists = true;
        },
    

    大致逻辑都在这里了
    最后贴一下样式代码吧

    
    
  • 相关阅读:
    网络性能监控无法告诉你的 6 件事
    上半年绩效差,「营销分析报告」无从下手,这套模板领导一看就懂
    【Shell编程】Shell中的正则表达式
    经典双栈实现队列,注意遍历栈的判定条件修改。
    卡尔曼家族从零解剖-(07) 高斯分布积分为1,高斯分布线性变换依旧为高斯分布,两高斯函数乘积仍为高斯。
    对Java平台的理解
    【LeetCode每日一题:1769. 移动所有球到每个盒子所需的最小操作数~~~双重循环遍历模拟】
    英特尔:如何从“小芯片”布局到通用量子计算机
    c语言之字符串
    【Spring Boot】关系映射开发(二):一对多映射
  • 原文地址:https://blog.csdn.net/weixin_45324044/article/details/127089382