Javascript 如何从 FileList 中删除文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3144419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:25:32  来源:igfitidea点击:

How do I remove a file from the FileList

javascripthtmldrag-and-dropfilelist

提问by Heilemann

I'm building a drag-and-drop-to-upload web application using HTML5, and I'm dropping the files onto a div and of course fetching the dataTransfer object, which gives me the FileList.

我正在使用 HTML5 构建一个拖放式上传 Web 应用程序,我将文件拖放到 div 上,当然还获取了 dataTransfer 对象,它为我提供了FileList

Now I want to remove some of the files, but I don't know how, or if it's even possible.

现在我想删除一些文件,但我不知道如何,或者是否有可能。

Preferably I'd like to just delete them from the FileList; I've got no use for them. But if that's not possible, should I instead write in checks in code that interacts with the FileList? That seems cumbersome.

最好我只想从 FileList 中删除它们;我对他们没有用。但是,如果这是不可能的,我是否应该在与 FileList 交互的代码中写入检查?那看起来很麻烦。

回答by Marcel Korpel

If you want to delete only several of the selected files: you can't. The File API Working Draftyou linked to contains a note:

如果您只想删除几个选定的文件:您不能。您链接到的文件 API 工作草案包含一个注释:

The HTMLInputElementinterface [HTML5] has a readonlyFileListattribute, […]
[emphasis mine]

HTMLInputElement接口[HTML5]有一个只读FileList属性,[...]
[重点煤矿]

Reading a bit of the HTML 5 Working Draft, I came across the Common inputelement APIs. It appears you can delete the entirefile list by setting the valueproperty of the inputobject to an empty string, like:

阅读了一些 HTML 5 工作草案,我遇到了Common inputelement APIs。看来您可以通过将对象的属性设置为空字符串来删除整个文件列表,例如:valueinput

document.getElementById('multifile').value = "";

BTW, the article Using files from web applicationsmight also be of interest.

顺便说一句,使用 Web 应用程序中的文件一文可能也很有趣。

回答by Roberto

This question has already been marked answered, but I'd like to share some information that might help others with using FileList.

这个问题已经被标记为已回答,但我想分享一些可能有助于其他人使用 FileList 的信息。

It would be convenient to treat a FileList as an array, but methods like sort, shift, pop, and slice don't work. As others have suggested, you can copy the FileList to an array. However, rather than using a loop, there's a simple one line solution to handle this conversion.

将 FileList 视为数组会很方便,但 sort、shift、pop 和 slice 等方法不起作用。正如其他人所建议的那样,您可以将 FileList 复制到一个数组中。但是,不是使用循环,而是有一个简单的单行解决方案来处理这种转换。

 // fileDialog.files is a FileList 

 var fileBuffer=[];

 // append the file list to an array
 Array.prototype.push.apply( fileBuffer, fileDialog.files ); // <-- here

 // And now you may manipulated the result as required

 // shift an item off the array
 var file = fileBuffer.shift(0,1);  // <-- works as expected
 console.info( file.name + ", " + file.size + ", " + file.type );

 // sort files by size
 fileBuffer.sort(function(a,b) {
    return a.size > b.size ? 1 : a.size < b.size ? -1 : 0;
 });

Tested OK in FF, Chrome, and IE10+

在 FF、Chrome 和 IE10+ 中测试正常

回答by adlr0

If you are targeting evergreen browsers (Chrome, Firefox, Edge, but also works in Safari 9+) or you can afford a polyfill, you can turn the FileList into an array by using Array.from()like this:

如果您的目标是常绿浏览器(Chrome、Firefox、Edge,但也适用于 Safari 9+)或者您负担得起 polyfill,您可以使用Array.from()如下方法将 FileList 转换为数组:

let fileArray = Array.from(fileList);

Then it's easy to handle the array of Files like any other array.

然后很容易File像处理任何其他数组一样处理s 数组。

回答by Vreenak

Since we are in the HTML5 realm, this is my solution. The gist is that you push the files to an Array instead of leaving them in a FileList, then using XHR2, you push the files to a FormData object. Example below.

由于我们在 HTML5 领域,这是我的解决方案。要点是将文件推送到 Array 而不是将它们留在 FileList 中,然后使用 XHR2,将文件推送到 FormData 对象。下面举例。

Node.prototype.replaceWith = function(node)
{
    this.parentNode.replaceChild(node, this);
};
if(window.File && window.FileList)
{
    var topicForm = document.getElementById("yourForm");
    topicForm.fileZone = document.getElementById("fileDropZoneElement");
    topicForm.fileZone.files = new Array();
    topicForm.fileZone.inputWindow = document.createElement("input");
    topicForm.fileZone.inputWindow.setAttribute("type", "file");
    topicForm.fileZone.inputWindow.setAttribute("multiple", "multiple");
    topicForm.onsubmit = function(event)
    {
        var request = new XMLHttpRequest();
        if(request.upload)
        {
            event.preventDefault();
            topicForm.ajax.value = "true";
            request.upload.onprogress = function(event)
            {
                var progress = event.loaded.toString() + " bytes transfered.";
                if(event.lengthComputable)
                progress = Math.round(event.loaded / event.total * 100).toString() + "%";
                topicForm.fileZone.innerHTML = progress.toString();
            };
            request.onload = function(event)
            {
                response = JSON.parse(request.responseText);
                // Handle the response here.
            };
            request.open(topicForm.method, topicForm.getAttribute("action"), true);
            var data = new FormData(topicForm);
            for(var i = 0, file; file = topicForm.fileZone.files[i]; i++)
                data.append("file" + i.toString(), file);
            request.send(data);
        }
    };
    topicForm.fileZone.firstChild.replaceWith(document.createTextNode("Drop files or click here."));
    var handleFiles = function(files)
    {
        for(var i = 0, file; file = files[i]; i++)
            topicForm.fileZone.files.push(file);
    };
    topicForm.fileZone.ondrop = function(event)
    {
        event.stopPropagation();
        event.preventDefault();
        handleFiles(event.dataTransfer.files);
    };
    topicForm.fileZone.inputWindow.onchange = function(event)
    {
        handleFiles(topicForm.fileZone.inputWindow.files);
    };
    topicForm.fileZone.ondragover = function(event)
    {
        event.stopPropagation();
        event.preventDefault();
    };
    topicForm.fileZone.onclick = function()
    {
        topicForm.fileZone.inputWindow.focus();
        topicForm.fileZone.inputWindow.click();
    };
}
else
    topicForm.fileZone.firstChild.replaceWith(document.createTextNode("It's time to update your browser."));

回答by MeVimalkumar

I have found very quick & short workaround for this. Tested in many popular browsers (Chrome, Firefox, Safari);

我找到了非常快速和简短的解决方法。在许多流行的浏览器(Chrome、Firefox、Safari)中测试;

First, you have to convert FileList to an Array

首先,您必须将 FileList 转换为数组

var newFileList = Array.from(event.target.files);

to delete the particular element use this

删除特定元素使用此

newFileList.splice(index,1);

回答by A. Richards

I know this is an old question but it's ranking high on search engines in regards to this issue.

我知道这是一个老问题,但它在搜索引擎上就这个问题排名很高。

properties in the FileListobject cannot be deleted but at least on Firefox they can be changed. My workaround this issue was to add a property IsValid=trueto those files that passed check and IsValid=falseto those that didn't.

FileList对象中的属性无法删除,但至少在 Firefox上可以更改它们。我的解决方法是向IsValid=true通过检查的文件和IsValid=false未通过检查的文件添加属性。

then I just loop through the list to make sure that only the properties with IsValid=trueare added to FormData.

然后我只是遍历列表以确保只有 的属性IsValid=true被添加到FormData

回答by Nicholas Anderson

There might be a more elegant way to do this but here is my solution. With Jquery

可能有一种更优雅的方法来做到这一点,但这是我的解决方案。使用jQuery

fileEle.value = "";
var parEle = $(fileEle).parent();
var newEle = $(fileEle).clone()
$(fileEle).remove();
parEle.append(newEle);

Basically you cleat the value of the input. Clone it and put the clone in place of the old one.

基本上你清除输入的值。克隆它并将克隆放在旧的位置。

回答by Eric

This is extemporary, but I had the same problem which I solved this way. In my case I was uploading the files via XMLHttp request, so I was able to post the FileList cloned data through formdata appending. Functionality is that you can drag and drop or select multiple files as many times as you want (selecting files again won't reset the cloned FileList), remove any file you want from the (cloned) file list, and submit via xmlhttprequest whatever was left there.This is what I did. It is my first post here so code is a little messy. Sorry. Ah, and I had to use jQuery instead of $ as it was in Joomla script.

这是临时的,但我遇到了同样的问题,我以这种方式解决了这个问题。在我的情况下,我通过 XMLHttp 请求上传文件,所以我能够通过 formdata 附加发布 FileList 克隆数据。功能是您可以根据需要多次拖放或选择多个文件(再次选择文件不会重置克隆的文件列表),从(克隆的)文件列表中删除您想要的任何文件,并通过 xmlhttprequest 提交任何文件离开了那里。这就是我所做的。这是我在这里的第一篇文章,所以代码有点乱。对不起。啊,我不得不使用 jQuery 而不是 $,因为它在 Joomla 脚本中。

// some global variables
var clon = {};  // will be my FileList clone
var removedkeys = 0; // removed keys counter for later processing the request
var NextId = 0; // counter to add entries to the clone and not replace existing ones

jQuery(document).ready(function(){
    jQuery("#form input").change(function () {

    // making the clone
    var curFiles = this.files;
    // temporary object clone before copying info to the clone
    var temparr = jQuery.extend(true, {}, curFiles);
    // delete unnecessary FileList keys that were cloned
    delete temparr["length"];
    delete temparr["item"];

    if (Object.keys(clon).length === 0){
       jQuery.extend(true, clon, temparr);
    }else{
       var keysArr = Object.keys(clon);
       NextId = Math.max.apply(null, keysArr)+1; // FileList keys are numbers
       if (NextId < curFiles.length){ // a bug I found and had to solve for not replacing my temparr keys...
          NextId = curFiles.length;
       }
       for (var key in temparr) { // I have to rename new entries for not overwriting existing keys in clon
          if (temparr.hasOwnProperty(key)) {
             temparr[NextId] = temparr[key];
             delete temparr[key];
                // meter aca los cambios de id en los html tags con el nuevo NextId
                NextId++;
          }
       } 
       jQuery.extend(true, clon, temparr); // copy new entries to clon
    }

// modifying the html file list display

if (NextId === 0){
    jQuery("#filelist").html("");
    for(var i=0; i<curFiles.length; i++) {
        var f = curFiles[i];
        jQuery("#filelist").append("<p id=\"file"+i+"\" style=\'margin-bottom: 3px!important;\'>" + f.name + "<a style=\"float:right;cursor:pointer;\" onclick=\"BorrarFile("+i+")\">x</a></p>"); // the function BorrarFile will handle file deletion from the clone by file id
    }
}else{
    for(var i=0; i<curFiles.length; i++) {
        var f = curFiles[i];
        jQuery("#filelist").append("<p id=\"file"+(i+NextId-curFiles.length)+"\" style=\'margin-bottom: 3px!important;\'>" + f.name + "<a style=\"float:right;cursor:pointer;\" onclick=\"BorrarFile("+(i+NextId-curFiles.length)+")\">x</a></p>"); // yeap, i+NextId-curFiles.length actually gets it right
    }        
}
// update the total files count wherever you want
jQuery("#form p").text(Object.keys(clon).length + " file(s) selected");
    });
});

function BorrarFile(id){ // handling file deletion from clone
    jQuery("#file"+id).remove(); // remove the html filelist element
    delete clon[id]; // delete the entry
    removedkeys++; // add to removed keys counter
    if (Object.keys(clon).length === 0){
        jQuery("#form p").text(Object.keys(clon).length + " file(s) selected");
        jQuery("#fileToUpload").val(""); // I had to reset the form file input for my form check function before submission. Else it would send even though my clone was empty
    }else{
        jQuery("#form p").text(Object.keys(clon).length + " file(s) selected");
    }
}
// now my form check function

function check(){
    if( document.getElementById("fileToUpload").files.length == 0 ){
        alert("No file selected");
        return false;
    }else{
        var _validFileExtensions = [".pdf", ".PDF"]; // I wanted pdf files
        // retrieve input files
        var arrInputs = clon;

       // validating files
       for (var i = 0; i < Object.keys(arrInputs).length+removedkeys; i++) {
         if (typeof arrInputs[i]!="undefined"){
           var oInput = arrInputs[i];
           if (oInput.type == "application/pdf") {
               var sFileName = oInput.name;
               if (sFileName.length > 0) {
                   var blnValid = false;
                   for (var j = 0; j < _validFileExtensions.length; j++) {
                     var sCurExtension = _validFileExtensions[j];
                     if (sFileName.substr(sFileName.length - sCurExtension.length, sCurExtension.length).toLowerCase() == sCurExtension.toLowerCase()) {
                       blnValid = true;
                       break;
                     }
                   }
                  if (!blnValid) {
                    alert("Sorry, " + sFileName + " is invalid, allowed extensions are: " + _validFileExtensions.join(", "));
                    return false;
                  }
              }
           }else{
           alert("Sorry, " + arrInputs[0].name + " is invalid, allowed extensions are: " + _validFileExtensions.join(" or "));
           return false;
           }
         }
       }

    // proceed with the data appending and submission
    // here some hidden input values i had previously set. Now retrieving them for submission. My form wasn't actually even a form...
    var fecha = jQuery("#fecha").val();
    var vendor = jQuery("#vendor").val();
    var sku = jQuery("#sku").val();
    // create the formdata object
    var formData = new FormData();
    formData.append("fecha", fecha);
    formData.append("vendor", encodeURI(vendor));
    formData.append("sku", sku);
    // now appending the clone file data (finally!)
    var fila = clon; // i just did this because I had already written the following using the "fila" object, so I copy my clone again
    // the interesting part. As entries in my clone object aren't consecutive numbers I cannot iterate normally, so I came up with the following idea
    for (i = 0; i < Object.keys(fila).length+removedkeys; i++) { 
        if(typeof fila[i]!="undefined"){
            formData.append("fileToUpload[]", fila[i]); // VERY IMPORTANT the formdata key for the files HAS to be an array. It will be later retrieved as $_FILES['fileToUpload']['temp_name'][i]
        }
    }
    jQuery("#submitbtn").fadeOut("slow"); // remove the upload btn so it can't be used again
    jQuery("#drag").html(""); // clearing the output message element
    // start the request
    var xhttp = new XMLHttpRequest();
    xhttp.addEventListener("progress", function(e) {
            var done = e.position || e.loaded, total = e.totalSize || e.total;
        }, false);
        if ( xhttp.upload ) {
            xhttp.upload.onprogress = function(e) {
                var done = e.position || e.loaded, total = e.totalSize || e.total;
                var percent = done / total;
                jQuery("#drag").html(Math.round(percent * 100) + "%");
            };
        }
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
         var respuesta = this.responseText;
         jQuery("#drag").html(respuesta);
        }
      };
      xhttp.open("POST", "your_upload_handler.php", true);  
      xhttp.send(formData);
    return true;
    }
};

Now the html and styles for this. I'm quite a newbie but all this actually worked for me and took me a while to figure it out.

现在是这个的 html 和样式。我是一个新手,但所有这些实际上对我有用,我花了一段时间才弄明白。

<div id="form" class="formpos">
<!--    Select the pdf to upload:-->
  <input type="file" name="fileToUpload[]" id="fileToUpload" accept="application/pdf" multiple>
  <div><p id="drag">Drop your files here or click to select them</p>
  </div>
  <button id="submitbtn" onclick="return check()" >Upload</button>
// these inputs are passed with different names on the formdata. Be aware of that
// I was echoing this, so that's why I use the single quote for php variables
  <input type="hidden" id="fecha" name="fecha_copy" value="'.$fecha.'" />
  <input type="hidden" id="vendor" name="vendorname" value="'.$vendor.'" />
  <input type="hidden" id="sku" name="sku" value="'.$sku.'"" />
</div>
<h1 style="width: 500px!important;margin:20px auto 0px!important;font-size:24px!important;">File list:</h1>
<div id="filelist" style="width: 500px!important;margin:10px auto 0px!important;">Nothing selected yet</div>

The styles for that. I had to mark some of them !important to override Joomla behavior.

样式。我必须将其中一些标记为 !important 以覆盖 Joomla 行为。

.formpos{
  width: 500px;
  height: 200px;
  border: 4px dashed #999;
  margin: 30px auto 100px;
 }
.formpos  p{
  text-align: center!important;
  padding: 80px 30px 0px;
  color: #000;
}
.formpos  div{
  width: 100%!important;
  height: 100%!important;
  text-align: center!important;
  margin-bottom: 30px!important;
}
.formpos input{
  position: absolute!important;
  margin: 0!important;
  padding: 0!important;
  width: 500px!important;
  height: 200px!important;
  outline: none!important;
  opacity: 0!important;
}
.formpos button{
  margin: 0;
  color: #fff;
  background: #16a085;
  border: none;
  width: 508px;
  height: 35px;
  margin-left: -4px;
  border-radius: 4px;
  transition: all .2s ease;
  outline: none;
}
.formpos button:hover{
  background: #149174;
  color: #0C5645;
}
.formpos button:active{
  border:0;
}

I hope this helps.

我希望这有帮助。

回答by Sultanos

Thanks @Nicholas Anderson simple and straight , here is your code applied and working at my code using jquery.

感谢@Nicholas Anderson 简单而直接,这是您使用 jquery 应用和处理我的代码的代码。

HTML .

HTML 。

<input class="rangelog btn border-aero" id="file_fr" name="file_fr[]" multiple type="file" placeholder="{$labels_helpfiles_placeholder_file}">
<span style="cursor: pointer; cursor: hand;" onclick="cleanInputs($('#file_fr'))"><i class="fa fa-trash"></i> Empty chosen files</span>

JS CODE

代码

   function cleanInputs(fileEle){
    $(fileEle).val("");
    var parEle = $(fileEle).parent();
    var newEle = $(fileEle).clone()
    $(fileEle).remove();
    $(parEle).prepend(newEle);
}

回答by Neku80

If you have the luck to be sending a post request to the database with the files and you have the files you want to send in your DOM

如果您有幸将带有文件的发布请求发送到数据库,并且您有要在 DOM 中发送的文件

you can simply check if the file in the file list is present in your DOM, and of course if it's not you just don't send that element to de DB.

您可以简单地检查文件列表中的文件是否存在于您的 DOM 中,当然,如果不是,您就不要将该元素发送到 de DB。