1

//HTML

<div
  class="upload-wrap"
  @dragover.prevent
  @drop.prevent="hDrop"
>
  <input
    type="file"
    ref="addFiles"
    class="file-style"
    :accept="typeList"
    name="files"
    multiple
    @change="doAdd"
  />
  <input
    type="file"
    ref="addFolder"
    class="file-style"
    :accept="typeList"
    name="files"
    webkitdirectory
    multiple
    @change="doAdd"
  />
  <div class="drop">
    <el-icon style="font-size: 40px; color: #999">
      <upload-filled />
    </el-icon>
    <p class="tips">每张图片上传大小不超过5MB,每个视频不超过500MB,点击/拖拽上传</p>
    <el-button @click="addFilesBtn">添加文件</el-button>
    <el-button @click="addFolderBtn">添加文件夹</el-button>
  </div>
</div>

//css

.upload-wrap {
  position: relative;
  border: 1px dashed #ccc;
  width: 500px;
  height: 120px;
  .file-style {
    display: none;
  }
  .drop {
    margin-top: 10px;
    text-align: center;
    width: 100%;
    .tips {
      color: #999;
      font-size: 12px;
      margin-bottom: 10px;
    }
  }
}

//js

  let addFiles = ref(null);
  let addFolder = ref(null);
  const typeList = '.jpg, .jpeg, .png, .gif, .mp4, .mov';
  // 分割图片名称/后缀
  const getFileName = (fileName) => {
    const lastIndex = fileName.lastIndexOf('.');
    const arr = [fileName.slice(0, lastIndex), fileName.slice(lastIndex)];
    return arr;
  };
  // Upload组件其他参数
  const customRequest = async (files) => {
    const outsize = []; //超大列表
    const fileArr = []; //上传文件列表
    const size = item.size / 1024 / 1024;
    for (let i = 0; i < files.length; i++) {
      const item = files[i];
      // 上传队列去重
      const flag = upLoadList.find((el) => {
        return el.name === item.name;
      });
      if (!flag) {
        // 大于500M  加入超大队列
        if (size > 500) {
          outsize.push(item.name);
        } else {
          fileArr.push(item);
        }
      }
    }
    if (fileArr.length === 0) return;
    // 提示展示
    if (outsize.length > 0) {
      ElMessageBox({
        message: h('p', null, [
          outsize.length > 0 &&
            h(
              'p',
              { style: 'color: red;word-break: break-all' },
              `文件:${outsize}体积过大,已去除`
            ),
          h(
            'p',
            null,
            `剩余可上传数量${fileArr.length - outsize.length}个,确认是否上传`
          )
        ]),
        showCancelButton: true,
        confirmButtonText: '确认'
      })
        .then(() => {
          upListData(fileArr);
        })
        .catch(() => {
          // 取消本次上传
          const fileInput = document.querySelector('input[type="file"]');
          fileInput.value = '';
        });
    } else {
      upListData(fileArr);
    }
  };

  // 重组upList数据
  const upListData = (el) => {
    if (el.length === 0) {
      return;
    }
    for (let i = 0; i < el.length; i++) {
      const item = el[i];
      //  此处用响应式定义obj可以不等reader.onload先添加队列 后修改size跟src
      const obj = {
        src: '',
        name: item.name,
        state: '待上传',
        size: '',
        fileType: item.type,
        file: item
      };
      // 获取资源宽高,src等信息
      const reader = new FileReader();
      reader.readAsDataURL(item);
      reader.onload = (src) => {
        obj.src = src.target.result;
        // 获取资源宽高 区分图片还是视频
        if (file.type.startsWith('image/')) {
          const image = new Image();
          image.src = URL.createObjectURL(item);
          image.onload = (e) => {
            obj.size = [e.target.width, e.target.height];
            upLoadList.push(obj);
          };
        } else {
          const video = document.createElement('video');
          video.src = URL.createObjectURL(item);
          video.onloadedmetadata = () => {
            obj.size = [video.videoWidth, video.videoHeight];
            upLoadList.push(obj);
          };
        }
      };
      // upLoadList.push(obj)
    }
  };
  // 拖拽文件处理
  const webkitReadDataTransfer = (dataTransfer) => {
    let fileNum = dataTransfer.items.length;
    const files = [];
    // 递减计数,当fileNum为0,说明读取文件完毕
    const decrement = () => {
      if (--fileNum === 0) {
        customRequest(files);
      }
    };
    // 递归读取文件方法
    const readDirectory = (reader) => {
      // readEntries() 方法用于检索正在读取的目录中的目录条目,并将它们以数组的形式传递给提供的回调函数。
      reader.readEntries((entries) => {
        if (entries.length) {
          fileNum += entries.length;
          entries.forEach((entry) => {
            if (entry.isFile) {
              entry.file((file) => {
                readFiles(file, entry.fullPath);
              }, readError);
            } else if (entry.isDirectory) {
              readDirectory(entry.createReader());
            }
          });
          readDirectory(reader);
        } else {
          decrement();
        }
      }, readError);
    };
    // 文件对象
    const items = dataTransfer.items;
    // 拖拽文件遍历读取
    for (let i = 0; i < items.length; i++) {
      const entry = items[i].webkitGetAsEntry();
      if (!entry) {
        decrement();
        return;
      }
      if (entry.isFile) {
        readFiles(items[i].getAsFile(), entry.fullPath);
      } else {
        // entry.createReader() 读取目录。
        readDirectory(entry.createReader());
      }
    }
    function readFiles(file, fullPath) {
      if (typeList.includes(getFileName(file.name)[1].toLowerCase())) {
        // 图片或视频
        file.relativePath = fullPath.substring(1);
        files.push(file);
      }
      decrement();
    }
    function readError(fileError) {
      throw fileError;
    }
  };

  // 图片移入触发
  const hDrop = (e) => {
    webkitReadDataTransfer(e.dataTransfer);
  };
  // 点击添加文件
  const addFilesBtn = () => {
    addFiles.value.click();
  };
  // 点击添加文件夹
  const addFolderBtn = () => {
    addFolder.value.click();
  };
  // 选择添加文件
  const doAdd = (e) => {
    // 文件夹去除其他格式
    const newArr = Object.keys(e.target.files).map((key) => e.target.files[key]);
    const data = newArr.filter((el) => {
      return typeList.includes(getFileName(el.name)[1].toLowerCase());
    });
    customRequest(data);
  };

Victory
23 声望1 粉丝

专业CV战士