利用FormData实现上传文件功能

这篇博客详细介绍了使用HTML5、FormData和XMLHttpRequest实现文件上传,并结合jQuery动态展示上传进度条的过程。提供了两种不同的实现方式,包括文件选择、文件读取、上传进度监听和上传成功后的处理。
摘要由CSDN通过智能技术生成

实现步骤:

定义 UI 结构
验证是否选择了文件
FormData 中追加文件
使用 xhr 发起上传文件的请求
监听 onreadystatechange 事件

    <link rel="stylesheet" href="./lib/bootstrap.css" />
        
    <script src="./lib/jquery.js"></script>
    <!-- 1. 文件选择框 -->
    <input type="file" id="file1" />  <br />   
    <!-- 2. 上传按钮 -->
    <button id="btnUpload">上传文件</button><br />

    <!-- bootstrap 中的进度条 -->
    <div class="progress" style="width: 500px; margin: 15px 10px">
      <div
        class="progress-bar progress-bar-striped active"
        style="width: 0%"
        id="percent"
      >
        0%
      </div>
    </div>

    <!-- 3. 显示上传到服务器上的图片 -->
    <img src="" alt="" id="img" width="400" />
      // 1. 获取上传文件的按钮
      const btn = document.querySelector("#btnUpload");

      // 2. 为按钮添加 click 事件监听
      btn.addEventListener("click", function () {
        // 3. 获取到选择的文件列表
        const files = document.querySelector("#file1").files;
        if (files.length <= 0) {
          return alert("请选择文件");
        }

        //4.向FormData中追加文件
        const fd = new FormData();
        //将用户选择的文件添加到 FormData 中
        fd.append("avatar", files[0]);

        //5.使用 xhr 发起上传文件的请求
        const xhr = new XMLHttpRequest();

        //5.1 监听onreadystatechange事件
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4 && xhr.status === 200) {
            const data = JSON.parse(xhr.responseText);
            if (data.status === 200) {
              //上传成功
              // console.log(data);
              document.querySelector("#img").src =
                "http://www.liulongbin.top:3006" + data.url;
            } else {
              //上传失败
              console.log("文件上传失败!" + data.message);
            }
          }
        };

        //6.通过监听 xhr.upload.onprogress 事件,来获取到文件的上传进度
        xhr.upload.onprogress = function (e) {
          // e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
          if (e.lengthComputable) {
            // e.loaded 已传输的字节
            // e.total  需传输的总字节
            const percentComplete = Math.ceil((e.loaded / e.total) * 100);
            // console.log(percentComplete);

            //7.监听上传进度--动态设置进度条
            $('#percent').attr('style','width: ' + percentComplete + '%').html(percentComplete + '%');
          }
        };

        //8.监听上传完成的事件
        xhr.upload.onload = function(){
            $('#percent').removeClass().addClass('progress-bar progress-bar-success');
        };

        xhr.open("POST", "http://www.liulongbin.top:3006/api/upload/avatar");
        xhr.send(fd);
      });

方式2:

<!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>
    <link rel="stylesheet" href="../../../02bootstrap/css/bootstrap.css" />
    <script src="../../../02bootstrap/js/jquery-3.5.1.js"></script>
    <script src="../../../02bootstrap/js/bootstrap.js"></script>
    <style>
      td,
      th {
        text-align: center;
      }
    </style>
  </head>
  <body>
    <form action="" id="form">
      <p>
        请选择文件:
        <input type="file" name="file" id="file" multiple />
      </p>
      <p>
        <input type="button" value="上传" id="upload" />
      </p>
    </form>
    <div id="previews">
      <table class="table table-bordered table-active" id="tb">
        <thead>
          <tr>
            <th width="10%">文件名称</th>
            <th width="10%">文件大小(KB)</th>
            <th width="10%">文件类型</th>
            <th width="35%">预览图</th>
            <th width="35%">上传进度</th>
          </tr>
        </thead>
        <tbody id="tbody"></tbody>
      </table>
    </div>
    <script>
      // 0. 获取相关元素
      const file = document.getElementById("file");
      const tbody = document.getElementById("tbody");
      const upload = document.getElementById("upload");

      // 1. 文件域如何取值(取文件)
      // console.log(document.getElementById("file").files);

      /**
       * 2. 取出的 fileList 怎么用
       * 通过 fileReader 去读取每一个 file 对应的内容,读取出文件内容,将文件内容渲染到图片标签上
       */
      // 给文件域添加事件--onchange事件
      file.onchange = function () {
        let files = this.files;
        // 在渲染文件之前先清空之前内容区域的内容
        tbody.innerHTML = "";
        for (let i = 0; i < files.length; i++) {
          // 获取文件输入流对象--用户读取文件内容
          let reader = new FileReader();
          // 异步,调用 readAsDataURL()  传入 file 对象读取该文件的内容
          reader.readAsDataURL(files[i]);
          reader.onload = function () {
            // 拿到读取的文件内容
            let result = reader.result;
            let tr = document.createElement("tr");
            tr.innerHTML = `
                            <td>${files[i].name}</td>
                            <td>${Math.ceil(files[i].size / 1024)}KB</td>
                            <td>${files[i].type}</td>
                            <td>
                                <img src="${result}" width="200px" height="120px" />
                            </td>
                            <td>
                                <div class="progress">
                                    <div class="progress-bar progress-bar-animated progress-bar-striped" style="width: 0%"></div>
                                </div>
                            </td>
                            `;
            // console.log(tr.nodeType);
            tbody.appendChild(tr);
          };
        }
      };

      // 3. 文件上传
      upload.onclick = function () {
        uploadFile();
      };

      // 定义全局变量 index 记录上传序号
      let index = 0;

      // 4. 封装文件上传函数
      function uploadFile() {
        // 获取到选择的文件列表
        const files = document.querySelector("#file").files;

        if (files.length <= 0) {
          return alert("请选择文件");
        }

        // 准备数据
        const formData = new FormData();
        let file = files[index];
        formData.append("file", file);

        // 调用接口完成上传
        const xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4 && xhr.status === 200) {
            const data = JSON.parse(xhr.responseText);
            if (data.status === 200) {
            //   alert("上传成功!");
              console.log("上传成功!");
              console.log(data.url);
              // 每上传一个文件 index 就加1
              index++;
              // 当 index 小于上传的文件的个数时可以上传,否则结束上传并将 index = 0,便于下次上传
              if (index < files.length) {
                uploadFile();
              } else {
                index = 0;
              }
            } else {
              console.log("文件上传失败!");
              console.log(data.message);
            }
          }
        };

        // 进度条--通过监听 xhr.upload.onprogress 事件,来获取到文件的上传进度
        xhr.upload.onprogress = function (e) {
          // e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
          if (e.lengthComputable) {
            // e.loaded 已传输的字节
            // e.total  需传输的总字节
            const percentComplete = Math.ceil((e.loaded / e.total) * 100) + "%";
            // 监听上传进度--动态设置进度条
            document.querySelectorAll(".progress-bar")[index].style.width = percentComplete;
          }
        };

        xhr.open("POST", "http://www.liulongbin.top:3006/api/upload/avatar");
        xhr.send(formData);
      }
    </script>
  </body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白小白从不日白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值