Html 从多个“输入:文件”中删除文件列表项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16943605/
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-29 09:06:51  来源:igfitidea点击:

Remove a FileList item from a multiple "input:file"

javascripthtmlinputupload

提问by

I have this DOM:

我有这个 DOM:

var id = 0;

$('input:file#upload')[0].files[ id ]

That get's the first file on the 0th index. File properties are listed and all works, but...

那就是第 0 个索引上的第一个文件。列出了文件属性并且一切正常,但是...

How do we remove items from the DOM's [object FileList]with JavaScript?

我们如何[object FileList]使用 JavaScript从 DOM 中删除项目?

采纳答案by Imran Latif

I' am afraid that you cannot delete objects from FileList objectdirectly. Just assign $('input:file#upload')[0].filesto an Arrayand then remove items from that array using spliceor method of your choice and then use that Array.

恐怕您无法FileList object直接从中删除对象。只需分配$('input:file#upload')[0].files给 anArray然后使用splice您选择的方法从该数组中删除项目,然后使用 that Array

回答by Endless

Finally found a way! I knew before that input.fileswould accept a FileList but the only way to get it was throught a drag and drop event.

终于找到方法了!我之前input.files就知道会接受 FileList,但获得它的唯一方法是通过拖放事件。

But now i know how to construct a own FileList!

但是现在我知道如何构建自己的 FileList 了!

This works in chrome (and maybe some other)

这适用于 chrome(也许还有其他一些)

const dt = new DataTransfer()
dt.items.add(new File([], 'a.txt'))
input.files = dt.files

// This will remove the fist item when selecting many files
input.onchange = () => {
  const dt = new DataTransfer()

  for (let file of input.files)
    if (file !== input.files[0]) 
      dt.items.add(file)

  input.onchange = null // remove event listener
  input.files = dt.files // this will trigger a change event
}
<input type="file" multiple id="input">

This works in Firefox

这适用于 Firefox

const cd = new ClipboardEvent("").clipboardData
cd.items.add(new File(['a'], 'a.txt'))
input.files = cd.files

// This will remove the fist item when selecting many files
input.onchange = () => {
  const dt = new DataTransfer()

  for (let file of input.files)
    if (file !== input.files[0]) 
      dt.items.add(file)

  input.onchange = null // remove event listener
  input.files = dt.files // this will trigger a change event
}
<input type="file" multiple id="input">

The thing is you need to loop over each file in the input, add those you still want to keep and assign the file.files with the new list of files.

问题是您需要遍历输入中的每个文件,添加您仍然想要保留的文件,并使用新的文件列表分配 file.files。

回答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 Volfegan

The most practical way to remove FileList objectis to just remove the file input itself from the DOM and re-append it again. This will remove all the items from the file list.

最实用的删除方法FileList object是从 DOM 中删除文件输入本身,然后再次重新附加它。这将从文件列表中删除所有项目。

I know a lot of people will say this is not an elegant solution, but it very easy to implement, a better approach for most cases, and you can do what is important with the input file, validation!

我知道很多人会说这不是一个优雅的解决方案,但它很容易实现,在大多数情况下是一种更好的方法,并且您可以对输入文件执行重要的操作,验证!

By now you see that to control the FileList objectis hard. If you really need to manipulate an individual file item, read Multi-File Uploads and Multiple Selects (Part 2), by RAYMOND CAMDEN . I prefer to just make the user select the files again (if he done goofy) and give him an error message of what went wrong. This will not make the user experience bad.

到现在为止,您会看到FileList object很难控制。如果您确实需要操作单个文件项,请阅读RAYMOND CAMDEN 的 Multi-File Uploads and Multiple Selects(第 2 部分) 。我更喜欢让用户再次选择文件(如果他做傻事)并给他一条错误消息,告诉他出了什么问题。这不会使用户体验变差。

As a reminder, be aware that input file brings security weakness (Vulnerability: Unrestricted File Upload).

提醒一下,请注意输入文件会带来安全漏洞(漏洞:无限制文件上传)。

Since this post didn't really answer the question, I know it won't get any points, but really consider the alternatives. For my case when I was implementing deleting a file object item, it didn't make sense continuing the upload after some file didn't pass the validation, even if some files were ok. In the end, the user would still have to open the input file and redo the process. So, for my case, this feature was just adding complexity, and it was not in the specification this much control for an input file.

由于这篇文章并没有真正回答这个问题,我知道它不会得到任何分数,但真的要考虑替代方案。对于我实现删除文件对象项时的情况,即使某些文件没问题,在某些文件未通过验证后继续上传也没有意义。最后,用户仍然必须打开输入文件并重做该过程。因此,就我而言,此功能只是增加了复杂性,并且在规范中并没有对输入文件进行如此多的控制。

Bellow an example with validation that deletes all the FileList objectwhen fails:

下面是一个带有验证的示例,该示例删除所有FileList object失败时:

function validateFormfile(inputTypeFile_id) {
  $(inputTypeFile_id).change((event) => {
    //check if files were select, if not, nothing is done
    if (event.target.files.length > 0) {
      let fileName;
      let totalsize = 0;
      let notvalidate = false;
      for (let i = 0; i < event.target.files.length; i++) {

        fileName = event.target.files[i].name;
        fileSize = event.target.files[i].size;
        if (fileName != undefined || fileName != "") {

          if (validate_fileExtension(fileName) === false) {
            notvalidate = true;
            let errorMessage = "File upload must be of 'audio', 'image', 'video', 'text', or 'pdf' format!";
            //write you error function to show error to user
            //alertpanel(errorMessage);
            console.log(errorMessage);
            break;
          }
          totalsize += Number(event.target.files[i].size);
          console.log(fileName, fileSize, "bytes");
        }
      }

      //check if file size is bigger than maxsize
      let maxsize = 10 * 1024 * 1024; //10Mb
      if (totalsize > maxsize && notvalidate === false) {
        notvalidate = true;
        let errorMessage = `Upload files cannot exceed the maximum of ${maxsize} bytes.`;
        //write you error function to show error to user
        //alertpanel(errorMessage);
        console.log(errorMessage);
      }

      if (notvalidate) {
        //select the node where to append the input file
        let inputlabel = $(inputTypeFile_id).siblings().first();
      
        //we delete the input file element to delete its FileList object content and re-append to the DOM
        $(inputTypeFile_id).remove();
        let input_file = $('<input type="file" id="upload" name="upload" accept="application/pdf, text/plain, audio/*, video/*, image/*" multiple required>');

        //append the input file after the selected inputlabel node 
        inputlabel.after(input_file);

        //re init any event listener for the re-appended element
        validateFormfile(inputTypeFile_id);
      }
    }
  });
}

function validate_fileExtension(fileName) {
  let image_extensions = new Array("bmp", "jpg", "jpeg", "jpe", "jfif", "png", "gif");
  let text_extensions = new Array("txt", "pdf");
  let video_extensions = new Array("avi", "mpeg", "mpg", "mp4", "mkv");
  let audio_extensions = new Array("mp3", "acc", "wav", "ogg");
  let allowed_extensions = image_extensions.concat(text_extensions, video_extensions, audio_extensions);
  // split function will split the fileName by dot(.), and pop function will pop the last element from the array which will give you the extension as well. If there will be no extension then it will return the fileName.
  let file_extension = fileName.split('.').pop().toLowerCase();

  for (let i = 0; i <= allowed_extensions.length; i++) {
    if (allowed_extensions[i] == file_extension) {
      return true; // valid file extension
    }
  }
  return false;
}
//init event listener to input file
$(document).ready(
    validateFormfile("#upload")
  );
label,
input {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<label for="upload">Choose File(s) (Max: 10Mb)</label>
<input type="file" id="upload" name="upload" accept="application/pdf, text/plain, audio/*, video/*, image/*" multiple required>
<br><small>text|pdf|audio|image|video</small>

I hope this helps in some way.

我希望这在某种程度上有所帮助。

回答by Rush.2707

No, We can make it removable. I implemented this and it works definitely.

不,我们可以把它拆下来。我实现了这个,它绝对有效。

First you need to initialize this variables

首先你需要初始化这个变量

var newImageObj = [];
var ImageNo = 0;

Then write this code on file input's change

然后在文件输入的更改上编写此代码

$("#exampleInputFileProduct").change(function () {

            var fileUpload = document.getElementById("exampleInputFileProduct");

            //$("#mainImages").html('');
            //$("#subImages").html('');

            if (typeof (FileReader) != "undefined") {

                //Here Check File Extension
                var regex = /^([a-zA-Z0-9\s_\.\-:])+(.jpg|.jpeg|.gif|.png)$/;


                for (var i = 0; i < fileUpload.files.length; i++) {
                    var j = 0;
                    var file = fileUpload.files[i];
                    var NewFile = fileUpload.files[i];
                    //Here Check File Size 1MB = 1000000 Bytes
                    if (file.size < 2048000) {
                        if (regex.test(file.name.toLowerCase())) {
                            var reader = new FileReader();
                            reader.onload = function (e) {

                                if ($("#mainImages").find(".item").attr("id") == "FirstSlider") {
                                    $("#mainImages").html('');
                                    $("#subImages").html('');
                                    $("#subImages").append("<div class='item active'></div>");
                                }

                                if ($("#mainImages").find(".item").hasClass("active")) {
                                    $("#mainImages").append("<div class='item " + ImageNo + "_CClass\'><i class='fa fa-times customIcon' onclick='RemoveImage(\"" + ImageNo + "_CClass\",\"" + fileUpload.files[j].name.toLowerCase() + "\")'></i><img class='CImage' src='" + e.target.result + "' alt='' /></div>");
                                } else {
                                    $("#mainImages").append("<div class='item active " + ImageNo + "_CClass'><i class='fa fa-times customIcon' onclick='RemoveImage(\"" + ImageNo + "_CClass\",\"" + fileUpload.files[j].name.toLowerCase() + "\")'></i><img class='CImage' src='" + e.target.result + "' alt='' /></div>");
                                }

                                //if ($("#subImages").find(".item").length == 0) {
                                //    $("#subImages").append("<div class='item active'></div>");
                                //} else {
                                if (($("#subImages").find(".item").find("div").length / 5) >= $("#subImages").find(".item").length) {
                                    $("#subImages").append("<div class='item'></div>");
                                }
                                //}

                                var append = 0;

                                $.each($("#subImages").find(".item"), function (p, pelement) {
                                    if (append == 0) {
                                        if ($(pelement).find("div").length != 5) {
                                            var newID = $(pelement).find("div").length;
                                            newID = newID;
                                            $(pelement).append("<div onclick='LoadImage(\"" + ImageNo + "_CClass\")' data-slide-to='" + newID + "' class='thumb " + ImageNo + "_CClass'> <img src='" + e.target.result + "' alt=''></div>");
                                            append = append + 1;
                                        }
                                    }
                                })

                                j = j + 1;

                                ImageNo = ImageNo + 1;
                            }

                            newImageObj.push(file);

                            reader.readAsDataURL(file);
                        }
                    }
                }
            } else {
                alert("This browser does not support HTML5 FileReader.");
            }
        });

Then at last this 2 functions will help to do the rest

然后最后这 2 个函数将帮助完成剩下的工作

function LoadImage(objclass) {
            $("#mainImages").find(".item").removeClass("active");
            $("#mainImages").find("." + objclass + "").addClass("active");
        }

        function RemoveImage(objclass, ImageName) {

            $.each(newImageObj, function (e, element) {
                if ($(this)[0].name.toLowerCase().trim() == ImageName.trim()) {
                    newImageObj.pop(this);
                }
            });

            $("#mainImages").find("." + objclass + "").remove();
            $("#subImages").find(".item").find("." + objclass + "").remove();

            if ($("#mainImages").find(".item").length == 0) {
                $("#mainImages").append("<div class='item active'><i class='fa fa-times customIcon'></i><img class='CImage' src='/Content/img/DefaultProduct.gif' alt='' /></div>");
                $("#subImages").append("<div class='item active'><div data-target='#carousel' data-slide-to='0' class='thumb'> <img src='/Content/img/DefaultProduct.gif' alt=''></div></div></div>");
            } else {
                $("#mainImages").find(".item").removeClass("active");
                $("#mainImages").find(".item:first-child").addClass("active");
                $("#subImages").find(".item").removeClass("active");
                $("#subImages").find(".item:first-child").addClass("active");
            }
        }

At last when you submit your form than take the files from the array

最后,当您提交表单时,而不是从数组中获取文件