6.2 參考:jquery ajax 上傳檔案並顯示進度條

目的

檔案在上傳時,前端的頁面顯示上傳的進度。這裡會用到 ajax 的技術,故此例僅提供給同學未來參考。

為了方便觀察:可將網速調慢

現在網路都滿快的,所以如果檔案太小,有時不會那麼明顯,因為會直接變成是進度 100%

那麼為了方便觀察,可透過以下方式,將網路速度調慢。

步驟:開啟開發者工具 → Network → No throttling → Fast 3G。(測完之後,記得調回原來的)

ajax 傳送檔案

結果示意

進度條的 CodePen 參考:https://codepen.io/carlos411/pen/QWPyzVW

建立 html5/file/file2_upload.html 檔案,內容如下:

<!DOCTYPE html>
<html lang="zh-Hant">
  <head>
    <meta charset="utf-8">
    <title>File API:檔案上傳進度顯示</title>
    <style>
      img.preview{
        width: 200px;
      }
      ul{
        list-style: none;
        margin: 0;
        padding: 0;
      }
      ul > li{
        display: inline-block;
        vertical-align: top;
      }

      div.progressbar{
        height: 20px;
        background-color: #e9ecef;
        border-radius: 8px;
        position: relative;
        overflow: hidden;
        margin-bottom: 30px;
      }
      div.progressbar > span.progress{
        position: absolute;
        top: 0;
        left: 0;
        height: 100%;
        box-sizing: border-box;
        background-color: #007bff;
      }
    </style>
  </head>
  <body>
    <input type="file" id="the_file" accept="image/*" multiple>
    <ul class="picture_list"></ul>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script>

      var the_file_element = document.getElementById("the_file");
      the_file_element.addEventListener("change", function(e){

        var picture_list = document.getElementsByClassName("picture_list")[0];
        picture_list.innerHTML = ""; // 清空

        var that = this; // 將 this 用 that 來替代,底下程式會用到

        // 跑每個使用者選的檔案
        for (let i = 0; i < this.files.length; i++) {

          let reader = new FileReader(); // 用來讀取檔案

          reader.readAsDataURL(this.files[i]); // 讀取檔案

          reader.addEventListener("load", function (e) {
            console.log("load 事件");
            console.log(e);

            // 建立 li 標籤,加上屬性、圖片、進度條,最後放入 ul 標籤裡
            let li_html = `
              <li data-index="${i}">
                <img class="preview" src="${reader.result}">
                <div class="progressbar"><span class="progress" style="width: 0%;"></span></div>
              </li>
            `;
            picture_list.insertAdjacentHTML("beforeend", li_html); // 加進節點

            // 這裡實際將檔案傳送出去:ajax 技術
            
          });

        }

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

使用 jQuery ajax 傳送檔案

在上述程式碼當中,有個註解是「// 這裡實際將檔案傳送出去:ajax 技術」,在其底下加入以下程式碼即可:

// 這裡實際將檔案傳送出去:ajax 技術
let form_data = new FormData();
form_data.append('the_file', that.files[i]);

$.ajax({
  url: "https://notes.webmix.cc/html5_tutorial/file/file_receive.php",
  type: "POST",
  data: form_data,
  contentType: false,
  cache: false,
  processData:false,

  xhr: function() {
    //console.log("這是第幾個索引:" + i);
    var myXhr = $.ajaxSettings.xhr();
    if(myXhr.upload){
      myXhr.upload.addEventListener('progress', function(evt) {
        console.log("progress 事件觸發");
        
        var progress_el = document.querySelector('.picture_list li[data-index="' + i + '"] span.progress');

        if (evt.lengthComputable) {
          var loaded = (evt.loaded / evt.total);
          if (loaded <= 1) {
            //console.log(evt.loaded / evt.total)
            var percent = loaded * 100;
            console.log("進度:" + percent + "%");
            
            // 改變介面進度條的百分比
            progress_el.setAttribute("style", "width: " + percent + "%;");
          }
        }

      }, false);
    }
    return myXhr;
  },

  success: function(data_obj) { // 從伺服器回傳的資料
    //console.log("success");
    alert("傳送完成");
    console.log(data_obj);

  }
});
  • evt.lengthComputable:檔案大小是否可被計算。會回傳 truefalse

  • evt.loaded:檔案已傳多少。

  • evt.total:要傳的總大小是多少。

參考:後端 PHP 程式碼接收檔案

<?php
// 傳送出去的編碼,設定為 utf-8
header('Content-Type: text/html; charset=utf-8');

// 顯示錯誤資訊
ini_set("display_errors", "On");
error_reporting(E_ALL & ~E_NOTICE);

// 取得上傳檔案的副檔名
$new_array = explode(".", $_FILES['the_file']['name']);
$ext = end($new_array);

$target_dir = "./upload/";                                         // 存檔的相對路徑
$new_filename = time() . "_" . rand(10,100) . "." . $ext;          // 新的檔名
$target_file = $target_dir . $new_filename;                        // 存的位置 + 檔名
move_uploaded_file($_FILES["the_file"]["tmp_name"], $target_file); // 檔案真的存下來

// 回傳資料給前端
$arr = array('code' => "success");
echo json_encode($arr);

Last updated