5.3 傳送檔案資料

若有包含檔案類型的資料

加上以下幾個參數:

  • contentType:若有傳送檔案,設定 false,也就是會將 header 資訊中的 Content-Type 設定成 multipart/form-data;預設是 application/x-www-form-urlencoded

  • processData:不用額外處理資料。例:如果是 GET,預設會將 data 物件資料字串化,放到網址。

  • cache:避免有圖片 cache 狀況。

  • xhr:改寫 XMLHttpRequest,然後回傳,主要是要監聽 progress 事件。

$.ajax({
  url: "https://...",
  type: "POST",       // 傳送資料有包含檔案,必須是 POST
  data: "物件",
  dataType: "json",
  
  
  
  
  contentType: false,  // 若有傳送檔案,設定 false,也就是將 Content-Type 設定成 multipart/form-data;預設是 application/x-www-form-urlencoded
  processData: false,  // 不用額外處理資料。例:如果是 GET,預設會將 data 物件資料字串化,放到網址
  cache: false,        // 避免有圖片 cache 狀況
  
  xhr: function() { // 改寫 XMLHttpRequest,然後回傳
    //var myXhr = $.ajaxSettings.xhr(); // jQuery 的寫法,可以取得 XMLHttpRequest 物件
    let myXhr = new XMLHttpRequest(); // 取得 XMLHttpRequest 物件
    if(myXhr.upload){
      // 在 upload 上,綁定 progress 事件
      myXhr.upload.addEventListener('progress', function(e) { // 監聽 progress 事件
        if(e.lengthComputable){
          progress_percent = parseInt((e.loaded / e.total) * 100);
        }
      });
      
    }
    return myXhr;
  },
  
  
  
  
  
  beforeSend: function(){
  },
  headers: {
    // "X-CSRF-Token":"abcde"   
  },
  statusCode: {
    200: function (res) {
    },
    404: function (res) {
    },
    500: function (res) {
    }
  },
  success: function(data){
    console.log(data);
  },
  error: function(xhr){
    console.log(xhr);
  },
  complete: function(xhr){
    console.log(xhr);
  }
});

jQuery 傳檔範例

完整範立:建立 ajax/practice/upload_file.html檔案,內容如下,留意 $.ajax 的部份:

<!DOCTYPE html>
<html lang="zh-Hant">
  <head>
    <meta charset="utf-8">
    <title>AJAX: 檔案上傳進度顯示</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>
    <!-- accept='image/*' -->
    <input type="file" id="the_file" accept="image/*" multiple>
    <ul class="picture_list"></ul>

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

      $(function(){

        $("#the_file").on("change", function(e){

          // 清空
          $("ul.picture_list").html("");

          //console.log("here");
          //console.log(this);

          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("here2");
              //console.log(this);

              // 加進節點
              $("ul.picture_list").append(`
                <li data-index="${i}">
                  <img class="preview" src="${reader.result}">
                  <div class="progressbar"><span class="progress" style="width: 0%;"></span></div>
                </li>
              `);

              // 這裡實際將檔案傳送出去: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,
                dataType: "json",
                
                contentType: false,
                cache: false,
                processData:false,

                xhr: function() {
                  console.log("嗨 xhr()");

                  let myXhr = new XMLHttpRequest();
                  if(myXhr.upload){

                    myXhr.upload.addEventListener('progress', function(evt) {
                      console.log("progress 事件觸發,印出事件物件:");
                      console.log(evt)
                      // evt.lengthComputable: 是否可被計算
                      // evt.loaded: 已傳了多少
                      // evt.total: 總共有多少要傳
                      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 + "%");

                          // 找到對應的進度條
                          $("ul.picture_list li[data-index=" + i + "]").find("span.progress").attr("style", "width: " + percent + "%;");
                        }
                      }

                    });
                  }
                  return myXhr;

                },

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

                }
              });

            });


          }

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

執行 http://127.0.0.1:5500/practice/upload_file.html 測試看看。

Last updated