Skip to content
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .upload-container {
      width: 500px;
      height: 100%;
      border: 1px solid #ebebeb;
      margin: 0 auto;
      margin-top: 50px;
      box-shadow: 3px 3px rgba(0, 0, 0, .3);
      padding: 0 30px;
      padding-bottom: 50px;
    }

    .upload-container .upload-btn {
      margin-top: 10px;
    }

    .upload-container .upload-btn .disabled {
      background-color: #dddddd !important;
    }

    .upload-container .upload-btn .select, .submit{
      height: 32px;
      background-color: #409eff;
      font-size: 12px;
      border: none;
      border-radius: 3px;
      color: #fff;
    }

    .upload-container .upload-btn .submit {
      margin-left: 10px;
    }
    
    .upload-container .upload-tip {
      font-size: 12px;
      color: #606266;
      margin-top: 10px;
    }

    .upload-container .upload-list {
      width: 360px;
    }

    .upload-container .upload-list .list {
      height: 26px;
      color: #606266;
      font-size: 14px;
      margin-top: 10px;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .upload-container .upload-list .list .left .file {
      width: 14px;
      height: 14px;
    }

    .upload-container .upload-list .list .right .delete {
      width: 14px;
      height: 14px;
    }
  </style>
</head>
<body>
  <section class="upload-container">
    <input 
      name="upload-inp" 
      type="file" 
      multiple
      style="display: none;"
    >
    <div class="upload-btn">
      <button class="select">点击上传</button>
      <button class="submit">上传服务器</button>
    </div>
    <div class="upload-tip">
      只能上传JPG/PNG/JPEG/WEBP文件, 且大小不能超过500kb
    </div>
    <div class="upload-list">
      <!-- <div class="list">
        <div class="left">
          <img class="file" src="./static/imgs/file.png" alt="">
          <span>foo.jepg</span>
        </div>
        <div class="right">
          <img class="delete" src="./static/imgs/delete.png" alt="">
        </div>
      </div> -->
    </div>
  </section>

  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/qs/6.10.1/qs.js"></script>
  <script src="./request.js"></script>
  <script>
    let uploadContainer = document.querySelector('.upload-container'),
      uploadInp = uploadContainer.querySelector('[name=upload-inp]'),
      uploadBtn = uploadContainer.querySelector('.upload-btn'),
      uploadList = uploadContainer.querySelector('.upload-list'),
      select = uploadBtn.querySelector('.select'),
      submit = uploadBtn.querySelector('.submit'),
      _files = []

    // 点击上传文件按钮, 触发input的点击事件
    select.addEventListener('click', function () {
      if (isDisabled()) {
        // 按钮禁用
        return
      }

      uploadInp.click()
    })

    // 清除list
    function clearList (index) {
      if (typeof index === 'number') {
        // 删除指定
        _files = _files.filter((_, idx) => idx !== index)
        uploadList.removeChild(uploadList.children[index])
      } else {
        // 全部删除
        _files = []
        uploadList.innerHTML = ''
      }
    }

    // 禁用按钮
    function isDisabled () {
      return select.classList.contains('disabled') || submit.classList.contains('disabled')
    }

    // 选择图片时的处理
    uploadInp.addEventListener('change', function () {
      let isPass = true,
        tempFiles = [] // 本次选择中能够通过的图片

      Array.prototype.forEach.call(this.files, file => {
        if (!/(jpg|png|jepg|webp)/i.test(file.type)) {
          // 限制图片类型
          isPass = false
        } else if (file.size > 500 * 1024) {
          // 再限制文件大小
          isPass = false
        } 

        if (isPass) {
          tempFiles.push(file)
        }
      })

      // 通过的图片添加到列表中
      tempFiles.forEach(file => {
        uploadList.innerHTML += `
          <div class="list">
            <div class="left">
              <img class="file" src="./static/imgs/file.png" alt="">
              <span>${file.name}</span>
            </div>
            <div class="right">
              <img class="delete" src="./static/imgs/delete.png" alt="">
            </div>
          </div>
        `
      })

      // 如果下次选择相同图片, 也让上传
      uploadInp.value = ''

      // 更新图片集合
      _files = _files.concat(tempFiles)
    })
  
    // 删除指定list
    uploadList.addEventListener('click', function (event) {
      if (!isDisabled() && event.target.className === 'delete') {
        // 获取下标
        let children = uploadList.children, // 所有list
          target = event.target.parentNode.parentNode, // 当前点击list
          index = Array.prototype.indexOf.call(children, target)
        
        clearList(index)
      }
    })

    // 上传图片
    submit.addEventListener('click', function () {
      if (isDisabled()) {
        // 按钮禁用
        return
      }

      if (_files.length === 0) {
        alert('你还没有选择图片~')
        return
      }

      // 上传过程中禁用按钮
      select.classList.toggle('disabled')
      submit.classList.toggle('disabled')

      // 上传图片 多张图片上传本质就是循环进行单张图片上传
      let result = _files.map((file, index) => {
        let formData = new FormData,
          list = uploadList.children[index], // list中的index和_files中的index是对应的
          right = list.querySelector('.right')

        formData.append('file', file)
        formData.append('filename', file.name)

        return instance.post('/upload-single', formData, {
          onUploadProgress (event) {
            // 设置进度
            right.innerHTML = ''
            right.innerText = (event.loaded / event.total * 100).toFixed(2) + '%'
          }
        })
          .then(response => {
            if (response.status === 0) {
              right.innerText = '100.00%'
              return Promise.resolve(response.statusText)
            } else {
              return Promise.reject(response.statusText)
            }
          })
          .catch(reason => {
            return Promise.reject(reason)
          })
      })

      Promise.all(result)
        .then(val => {
          alert('文件上传成功')
        }) 
        .catch(reason => {
          console.log(reason)
          alert('文件上传失败')
        })
        .finally(() => {
          _files = []
          clearList()
          // 取消禁用
          select.classList.toggle('disabled')
          submit.classList.toggle('disabled')
        })
    })
  </script>
</body>
</html>