18

XMLHttpRequest と file.slice を使用して、いくつかの大きなファイルをサーバーにアップロードしようとしています。
ドキュメントやその他のさまざまなリンクの助けを借りて、これを行うことができました。
大きなファイルのアップロードは時間のかかる作業なので、ユーザーに進行状況バーを提供したいと思います。
もう少し読んだ後、理論的にはまさに必要なことを行う例に出くわしました。
サンプルコードを取得し、それを自分のニーズに合わせることで、私は到達しました

var upload =
{
blobs: [],
pageName: '',
bytesPerChunk: 20 * 1024 * 1024,
currentChunk: 0,
loaded: 0,
total: 0,
file: null,
fileName: "",

uploadChunk: function (blob, fileName, fileType) {
    var xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.responseText) {
                // alert(xhr.responseText);
            }
        }
    };

    xhr.addEventListener("load", function (evt) {
        $("#dvProgressPrcent").html("100%");
        $get('dvProgress').style.width = '100%';
    }, false);

    xhr.addEventListener("progress", function (evt) {
        if (evt.lengthComputable) {
            var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
            $("#dvProgressPrcent").html(progress + "%");
            $get('dvProgress').style.width = progress + '%';
        }
    }, false);

    xhr.upload.addEventListener("progress", function (evt) {
        if (evt.lengthComputable) {
            var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
            $("#dvProgressPrcent").html(progress + "%");
            $get('dvProgress').style.width = progress + '%';
        }
    }, false);

    xhr.open('POST', upload.pageName, false);

    xhr.setRequestHeader("Content-Type", "multipart/form-data");
    xhr.setRequestHeader("X-File-Name", fileName);
    xhr.setRequestHeader("X-File-Type", fileType);
    xhr.send(blob);
},
upload: function (file) {
    var start = 0;
    var end = 0;
    var size = file.size;

    var date = new Date();
    upload.fileName = date.format("dd.MM.yyyy_HH.mm.ss") + "_" + file.name;

    upload.loaded = 0;
    upload.total = file.size;

    while (start < size) {
        end = start + upload.bytesPerChunk;
        if (end > size) {
            end = size;
        }

        var blob = file.slice(start, end);
        upload.uploadChunk(blob, upload.fileName, file.type);
        start = end;
        upload.loaded += start;
    }

    return upload.fileName;
}
};

呼び出しは次のようになります (検証なし)

upload.upload(document.getElementById("#upload").files[0]);

私の問題は、進捗イベントがトリガーされないことです。
私は xhr.addEventListener と xhr.upload.addEventListener を使用して (一度に両方とも) 進行状況イベントを試しましたが、トリガーされません。onreadystatechange および load イベントは問題なくトリガーされます。

私が間違っていることについて助けていただければ幸いです

更新
何度も試みた後、進行状況をシミュレートすることができましたが、別の問題に遭遇しました: アップロード中に Chrome の UI が更新されません。
コードは次のようになります

var upload =
{
    pageName: '',
    bytesPerChunk: 20 * 1024 * 1024,
    loaded: 0,
    total: 0,
    file: null,
    fileName: "",

    uploadFile: function () {
        var size = upload.file.size;

        if (upload.loaded > size) return;

        var end = upload.loaded + upload.bytesPerChunk;
        if (end > size) { end = size; }

        var blob = upload.file.slice(upload.loaded, end);

        var xhr = new XMLHttpRequest();

        xhr.open('POST', upload.pageName, false);

        xhr.setRequestHeader("Content-Type", "multipart/form-data");
        xhr.setRequestHeader("X-File-Name", upload.fileName);
        xhr.setRequestHeader("X-File-Type", upload.file.type);

        xhr.send(blob);

        upload.loaded += upload.bytesPerChunk;

        setTimeout(upload.updateProgress, 100);
        setTimeout(upload.uploadFile, 100);
    },
    upload: function (file) {
        upload.file = file;

        var date = new Date();
        upload.fileName = date.format("dd.MM.yyyy_HH.mm.ss") + "_" + file.name;

        upload.loaded = 0;
        upload.total = file.size;

        setTimeout(upload.uploadFile, 100);


        return upload.fileName;
    },
    updateProgress: function () {
        var progress = Math.ceil(((upload.loaded) / upload.total) * 100);
        if (progress > 100) progress = 100;

        $("#dvProgressPrcent").html(progress + "%");
        $get('dvProgress').style.width = progress + '%';
    }
};


更新 2
私はそれを修正し、クロムでも動作するプログレス バーをシミュレートすることができました。
以前のコード サンプルを、動作するもので更新しました。
一度にアップロードされるチャンクのサイズを減らすことで、バーをより頻繁に「更新」することができます。

4

2 に答える 2

7

https://stackoverflow.com/a/3694435/460368に記載されているように、次のことができます。

if(xhr.upload)
     xhr.upload.onprogress=upload.updateProgress;

updateProgress: function updateProgress(evt) 
{
   if (evt.lengthComputable) {
       var progress = Math.ceil(((upload.loaded + evt.loaded) / upload.total) * 100);
       $("#dvProgressPrcent").html(progress + "%");
       $get('dvProgress').style.width = progress + '%';
   }
}
于 2013-04-12T09:36:35.473 に答える
5

私の解決策があります:

function addImages(id) {
  var files = $("#files").prop("files");
  var file = files[loopGallery];
  var cList = files.length;

  var fd = new FormData();
  fd.append("file", file);
  fd.append("galerie", id);

  var xhr = new XMLHttpRequest();
  xhr.open("POST", "moduls/galerie/uploadimages.php", true);
  xhr.upload.onprogress = function(e) {
    var percentComplete = Math.ceil((e.loaded / e.total) * 100);
    $("#progress").css("display","");
    $("#progressText").text((loopGallery+1)+" z "+cList);
    $("#progressBar").css("width",percentComplete+"%");
  };

  xhr.onload = function() {
    if(this.status == 200) {
      $("#progressObsah").load("moduls/galerie/showimages.php?ids="+id);
      if((loopGallery+1) == cList) {
        loopGallery = 0;
      } else {
        $("#progressBar").css("width", "0%");  
        loopGallery++;
        addImages(id);
      }
    }
  }

  if(cList > 0) {
    xhr.send(fd);
  }
}
于 2015-01-16T18:05:18.167 に答える