使用HTML5实现文件上传并显示多个进度条

9
我正在通过XmlHTTPRequest和HTML5上传多个文件。 我已经将上传工作正常,但我想为每个文件上传添加一个进度条。 但是,我目前的代码对于所有文件上传都使用最后一个进度条,而不是每个上传使用自己的进度条。 这在客户端主要是视觉效果,但它真的很让我烦恼。 我认为事件会覆盖自身并使用最后一个进度条,但原因不明。这是我的代码:
var files = event.dataTransfer.files;

    // iterate over each file to upload, send a request, and attach progress event
    for (var i = 0, file; file = files[i]; i++) {
        var li = $("<li>" + file.name + "<div class='progressbar'></div></li>");

        // add the LI to the list of uploading files
        $("#uploads").append(li);

        // fade in the LI instead of just showing it
        li.hide().fadeIn();

        var xhr = new XMLHttpRequest();

            xhr.upload.addEventListener('progress', function(e) {
                var percent = parseInt(e.loaded / e.total * 100);
                li.find(".progressbar").width(percent);
            }, false);

            // check when the upload is finished
            xhr.onreadystatechange = stateChange;

            // setup and send the file
            xhr.open('POST', '/attachments', true);
            xhr.setRequestHeader('X-FILE-NAME', file.name);
            xhr.send(file);
        }

我猜测 "progress" 事件没有正确地读取 "li"。我怀疑我需要做某种绑定来告诉 "progress" 事件使用特定变量作为它的 "li",但我不确定我缺少什么。

2个回答

19

你的示例无法正常工作,因为你没有考虑到xhr进度事件是在所有列表项已经创建完成后才触发的。但是有很多方法可以使你的示例工作。关键是让xhr知道它正在处理哪个列表项。例如使用以下代码(我没有检查它是否有效。这段代码的目的是描述这个想法):

var xhr = new XMLHttpRequest();
xhr.upload.li = li;
xhr.upload.addEventListener('progress', function(e) {
    var percent = parseInt(e.loaded / e.total * 100);
    this.li.find(".progressbar").width(percent);
}, false);

7

我认为我找到了解决此问题的方法。它在我的一些测试中看起来是有效的。由于我不太擅长英语,因此我将分享我的示例脚本。如果您有任何问题,我会尽力解释更多 :)

// This is input object which type of file.  
var uploader = document.getElementById("fileUploader"); 

// We'll send a new post for each file.
for(var i=0, j=uploader.files.length; i<j; i++)
{
    var uploaderForm = new FormData(); // Create new FormData
    uploaderForm.append("action","upload"); // append extra parameters if you wish.
    uploaderForm.append("up_file",uploader.files[i]); // append the next file for upload

    var xhr = new XMLHttpRequest();

    xhr.addEventListener("loadstart", function(e){
        // generate unique id for progress bars. This is important because we'll use it on progress event for modifications
        this.progressId = "progress_" + Math.floor((Math.random() * 100000)); 

        // append progress elements to somewhere you want
        $("body").append('<div id="' + this.progressId + '" class="myCustomProgressBar" ></div>');
    });
    xhr.addEventListener("progress", function(e){
        var total = e.total;
        var loaded = e.loaded;
        var percent = (100 / total) * loaded; // Calculate percentage of loaded data

        // I animate progress object. Notice that i use "this.progressId" which i created on loadstart event.
        $("#" + this.progressId).animate({"width":300 * (percent / 100)}, 800);
    });

    xhr.open("POST","index.php");
    xhr.send(uploaderForm);
}

太棒了,谢谢!我最初尝试将所有文件添加到数组中的队列中,但那样行不通。直接从文件输入引用文件就很好:D你帮助我创建了这个:http://userscripts.org/scripts/show/158420 - Pluto
1
正如此示例所示,如果您想为每个文件单独拥有进度条,则必须为每个文件单独使用一个XHR,而不是将所有文件附加到一个XHR上。我希望进度事件上会有一些元数据,可以指示该事件提供统计信息的文件是哪个。 - Jon Hargett
对我来说,xhr.addEventListener("progress", function(e){})无效,必须使用xhr.upload.onprogress = function(e){}。 - maylon
@Mehmet,我试着运行你的代码,但是我在进度条方面遇到了问题。看起来进度条是在一个循环中,它们开始增加,然后在达到100%之后又开始减少回到0%,然后一直来回交替,如0%到100%再到0%。你能帮我一下吗?问候 - jhenrique

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接