【问题标题】:How to remove one specific selected file from input file control如何从输入文件控件中删除一个特定的选定文件
【发布时间】:2013-10-04 07:38:56
【问题描述】:

如何从输入文件控件中删除一个特定的选定文件?

我有一个输入文件控件,可以选择多个文件;但是,我想验证一个文件,如果它的扩展名错误,那么我应该从文件控件本身中删除该文件,这可能吗?

我尝试如下

<input type="file" name="fileToUpload" id="fileToUpload" multiple/>


<script> $("#fileToUpload")[0].files[0] </script>

以下是对象的屏幕截图,但我无法修改它

【问题讨论】:

  • 您打算如何处理这些文件?一旦用户上传它们,它们就会被复制到您的 tmp 文件夹中,并且它们的信息保存在您拥有的数组中,因此当您去处理它们时,只需跳过具有错误扩展名的那些...
  • 伙计们,它不是一个数组,它是一个属性为“0”、“1”、“2”的对象,所以我不能在这里进行数组操作
  • 不幸的是,您不能修改 FileList 中的文件,因为它们是只读的。创建一个新的 FileList 似乎也是不可能的。使用输入元素的 'accepts' 属性可以解决您的问题吗?您可以使用以下命令从 FileList 中删除所有文件:$("#fileToUpload")[0].value = ''

标签: javascript jquery file-upload


【解决方案1】:

正如其他人指出的那样,FileList 是只读的。不过,您可以通过将这些文件推送到单独的 Array 来解决此问题。然后,您可以使用该精选文件列表做任何您想做的事情。如果将它们上传到服务器是目标,您可以使用FileReader API。

下面是一个完全避免修改FileList 的方法。 步骤:

  1. 添加普通文件输入更改事件监听器
  2. 从更改事件中循环遍历每个文件,过滤以进行所需的验证
  3. 将有效文件推送到单独的数组中
  4. 使用FileReader API 读取本地文件
  5. 向服务器提交经过处理的有效文件

事件处理程序和基本文件循环代码:

var validatedFiles = [];
$("#fileToUpload").on("change", function (event) {
  var files = event.originalEvent.target.files;
  files.forEach(function (file) {
    if (file.name.matches(/something.txt/)) {
      validatedFiles.push(file); // Simplest case
    } else { 
      /* do something else */
    }
  });
});

下面是一个更复杂的文件循环版本,展示了如何使用FileReader API 将文件加载到浏览器中,并可选择将其作为 Base64 编码的 blob 提交到服务器。

  files.forEach(function (file) {
    if (file.name.matches(/something.txt/)) { // You could also do more complicated validation after processing the file client side
      var reader = new FileReader();
      // Setup listener
      reader.onload = (function (processedFile) {
        return function (e) {
          var fileData = { name : processedFile.name, fileData : e.target.result };

          // Submit individual file to server
          $.post("/your/url/here", fileData);

          // or add to list to submit as group later
          validatedFiles.push(fileData);
        };
      })(file);

      // Process file
      reader.readAsDataURL(file);
    } else { 
      /* still do something else */
    }
  });

关于使用FileReader API 的注意事项。 Base64 编码文件将使其大小增加约 30%。如果这不可接受,您将需要尝试其他方法。

【讨论】:

  • 嗨,只有一件事。 files 是一个 javascript 对象,因此您不能在其上使用 .forEach,您应该这样做 [].forEach.call(files, function(file){....})
  • 此解决方案仅在您不从表单提交上传文件时才有效
  • 而不是提交单个文件到服务器,我怎样才能让它发布整个数组?
  • @AndrewHubbs 那么如何通过多个文件输入再次验证文件附加?
  • 你在哪里从输入元素中删除文件?如果用户上传了 5 个文件,而您所做的只是处理一个 JavaScript 数组,那么他们仍然应该在输入按钮旁边看到“已选择 5 个文件”。
【解决方案2】:

html

<input id="fileInput" name="fileInput" type="file" />
<input onclick="clearFileInput()" type="button" value="Clear" />

javascript

    function clearFileInput(){
        var oldInput = document.getElementById("fileInput");

        var newInput = document.createElement("input");

        newInput.type = "file";
        newInput.id = oldInput.id;
        newInput.name = oldInput.name;
        newInput.className = oldInput.className;
        newInput.style.cssText = oldInput.style.cssText;
        // copy any other relevant attributes

        oldInput.parentNode.replaceChild(newInput, oldInput);
    }

【讨论】:

  • 不错的主意...我将更改“用newInput替换oldInput”替换为用于实际表单提交的真实hiddenInput,并保留@987654326 @ 原样。
【解决方案3】:

我想我也应该在这里添加我的评论(我已经在这里回答了:JavaScript delete File from FileList to be uploaded)

我找到了解决方法。这根本不需要 AJAX 请求,并且可以将表单发送到服务器。基本上,您可以创建一个hidden 或text 输入并将其value 属性设置为处理所选文件后创建的base64 字符串。

<input type=hidden value=${base64string} />

您可能会考虑创建多个输入文件而不是输入text 或hidden 的想法。这将不起作用,因为我们无法为其分配值。

此方法会将输入文件包含在发送到数据库的数据中,您可以忽略输入文件:

  • 在后端不考虑字段;
  • 您可以在序列化表单之前将disabled属性设置为输入文件;
  • 在发送数据之前删除 DOM 元素。

当您想要删除文件时,只需获取元素的索引并从 DOM 中删除输入元素(文本或隐藏)。

要求:

  • 当输入文件触发change 事件时,您需要编写逻辑以base64 格式转换文件并将所有文件存储在一个数组中。

优点:

  • 这基本上会给您很多控制权,您可以过滤、比较文件、检查文件大小、MIME 类型等等。

【讨论】:

    【解决方案4】:

    我知道这是一篇旧帖子,但我花了很长时间试图解决这个问题,所以我会发布我的解决方案。有一种方法可以用另一个 fileList 更新 fileField 元素的 fileList - 这可以通过 DataTransfer 完成:

    let updateFileList = function (fileField, index) {
      let fileBuffer = Array.from(fileField.files);
      fileBuffer.splice(index, 1);
    
      /** Code from: https://stackoverflow.com/a/47172409/8145428 */
      const dT = new ClipboardEvent('').clipboardData || // Firefox < 62 workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
        new DataTransfer(); // specs compliant (as of March 2018 only Chrome)
    
      for (let file of fileBuffer) { dT.items.add(file); }
      fileField.files = dT.files;
    }
    

    上述函数将fileField作为一个DOM Object,将fileField的fileList中的文件索引移除,并相应地更新传入的fileField。

    希望这可以节省其他人一些时间!

    How to set File objects and length property at FileList object where the files are also reflected at FormData object?

    【讨论】:

    • 很好的解决方案,但不幸的是它不适用于 iOS
    【解决方案5】:

    基于@liamthorne4 的回答,这是一个用于从列表中上传、列出和删除元素的有效解决方案,在 Firefox 和 Chrome 上进行了测试:

    HTML:

     <button onclick="uploadFile(event)">Upload files</button>
     <div id="listfiles" class="view_list"></div>
     <input class="hidden" type="file" id="input_file_id" onchange="fileList(event)" name="files[]" multiple>
    

    JS:

        function uploadFile(evt) {
            evt.preventDefault();
            $('#input_file_id').click();
        }
    
        function fileList(e) {
            var files = $('#input_file_id').prop("files");
            var names = $.map(files, function(val) { return val.name; });
            for (n in names)    {
                $("#listfiles").append("<div id=preload_"+n+" title='"+names[n]+"'><p>"+names[n]+"</p><a  onclick=deleteFile("+n+")>Delete</a></div>");
            }
        }
        function deleteFile(index)  {
            filelistall = $('#input_file_id').prop("files");
            var fileBuffer=[];
            Array.prototype.push.apply( fileBuffer, filelistall );
            fileBuffer.splice(index, 1);
            const dT = new ClipboardEvent('').clipboardData || new DataTransfer(); 
            for (let file of fileBuffer) { dT.items.add(file); }
            filelistall = $('#input_file_id').prop("files",dT.files);
            $("#preload_"+index).remove()
        }
    

    【讨论】:

      猜你喜欢
      • 2017-07-15
      • 1970-01-01
      • 1970-01-01
      • 2020-02-11
      • 2023-03-12
      • 2014-10-16
      • 2013-04-05
      • 1970-01-01
      • 2019-04-28
      相关资源
      最近更新 更多