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 .active {
      color: #409eff;
    }

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

    .upload-container .upload-list .list .right .delete, .complete {
      width: 14px;
      height: 14px;
    }

    .upload-container .upload-progress {
      display: none;
      margin-top: 20px;
      width: 300px;
      height: 6px;
      border-radius: 100px;
      background-color: #ddd;
    }

    .upload-container .upload-progress .progress {
      border-radius: 100px;
      height: 100%;
      width: 0%;
      background-color: #67c23a;
      transition: width .3s;
    }
  </style>
</head>
<body>
  <section class="upload-container">
    <input name="upload-inp" type="file" style="display: none;">
    <!-- <input name="upload-inp" type="file" accept=".png,.jpg,.jpeg,.webp" style="display: none;"> -->
    <div class="upload-btn">
      <button class="select" type="button">点击上传</button>
    </div>
    <div class="upload-tip">
      只能上传JPG/PNG/JPEG/WEBP文件, 且大小不能超过500kb
    </div>
    <div class="upload-list"></div>
    <div class="upload-progress">
      <div class="progress"></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="https://cdn.bootcdn.net/ajax/libs/spark-md5/3.0.0/spark-md5.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'),
      uploadProgress = uploadContainer.querySelector('.upload-progress'),
      progress = uploadProgress.querySelector('.progress'),
      select = uploadBtn.querySelector('.select'),
      _file = null

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

      if (_file) {
        alert('一次只能上传一张图片~')
        return
      }

      uploadInp.click()
    })

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

    // 图片转化为Buffer
    function img2Buffer (file) {
      return new Promise((resolve, reject) => {
        let fileReader = new FileReader
        fileReader.readAsArrayBuffer(file)
        fileReader.onload = function (event) {
          resolve(event.target.result)
        }
      })
    }

    // 根据内容生成hash名
    function hashHandler (buffer) {
      let spark = new sparkMD5.ArrayBuffer(),
        hash = null,
        suffix = /\.([0-9a-zA-Z]+)$/.exec(_file.filename)

      spark.append(buffer)
      hash = spark.end()
      return {
        buffer,
        hash,
        suffix,
        filename: hash + suffix
      }
    }

    // 文件切片
    function fileSlice (buffer) {
      let formData = new FormData
      // formData沿着原型链能找到slice方法, 被用于文件切片(单位B), 
      // 文件切片需要关注切片数量和切片大小
      // 先按照固定切片大小计算出需要的切片数量
      // 如果切片数量不大于限制值, 使用该方案
      // 如果切片数量大于限制值, 设置切片数量为限制值, 增大每个切片的大小
      
      let fileSize = _file.size // 文件大小
        limit = 100, // 最多分100个切片
        sliceSize = 1 * 1024, // 每个切片默认1kb
        sliceCount = Math.ceil(fileSize / sliceSize) // 所需切片数量
      
      if (sliceCount > limit) {
        // 超出切片数量限制
        sliceSize = fileSize / limit
        sliceCount = limit
      }

      // formData.slice(0, 1024) // 切[0, 1023)
      sliceSize

    }

    // 选择图片时的处理
    uploadInp.addEventListener('change', function () {
      _file = this.files[0]

      if (!_file) {
        return
      }

      if (isDisabled()) {
        // 按钮禁用
        return
      }

      if (!_file) {
        alert('你还没有选择图片~')
        return
      }

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

      // 显示进度条
      uploadProgress.style.display = 'block'

      console.log(_file)

      

    })
  </script>
</body>
</html>