如何从文件列表中删除文件

发布于 2024-09-07 08:45:53 字数 282 浏览 2 评论 0原文

我正在使用 HTML5 构建一个拖放上传 Web 应用程序,我将文件拖放到 div 上,当然还获取 dataTransfer 对象,这给了我 文件列表

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

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

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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

月依秋水 2024-09-14 08:45:54

我混合了许多开发人员的解决方案并得出了这个解决方案。
它在删除后更改原始数组列表,这意味着如果我们想保存图像,那么我们可以这样做。

<script>
    var images = [];
      function image_select() {
          var image = document.getElementById('image').files;
          for (i = 0; i < image.length; i++) {
            images.push({
                "name" : image[i].name,
                "url" : URL.createObjectURL(image[i]),
                "file" : image[i],
            })
          }
          document.getElementById('container').innerHTML = image_show();
      }

      function image_show() {
          var image = "";
          images.forEach((i) => {
             image += `<div class="image_container d-flex justify-content-center position-relative">
                  <img src="`+ i.url +`" alt="Image">
                  <span class="position-absolute" onclick="delete_image(`+ images.indexOf(i) +`)">×</span>
              </div>`;
          })
          return image;
      }
      function delete_image(e) {
        images.splice(e, 1);
        document.getElementById('container').innerHTML = image_show();

        const dt = new DataTransfer()
        const input = document.getElementById('image')
        const { files } = input

        for (let i = 0; i < files.length; i++) {
            const file = files[i]
            if (e !== i)
            dt.items.add(file);
        }

        input.files = dt.files;
        console.log(document.getElementById('image').files);
      }
</script>

******这是 html 代码 ******

<body>
    <div class="container mt-3 w-100">
        <div class="card shadow-sm w-100">
            <div class="card-header d-flex justify-content-between">
                <h4>Preview Multiple Images</h4>
                <form class="form" action="{{route('store')}}" method="post" id="form" enctype="multipart/form-data">
                    @csrf
                    <input type="file" name="image[]" id="image" multiple onchange="image_select()">
                    <button class="btn btn-sm btn-primary" type="submit">Submit</button>
                </form>
            </div>
            <div class="card-body d-flex flex-wrap justify-content-start" id="container">

            </div>
        </div>
    </div>
</body>

******** 这是 CSS 代码 ********

<style>
        .image_container {
    height: 120px;
    width: 200px;
    border-radius: 6px;
    overflow: hidden;
    margin: 10px;
}
.image_container img {
    height: 100%;
    width: auto;
    object-fit: cover;
}
.image_container span {
    top: -6px;
    right: 8px;
    color: red;
    font-size: 28px;
    font-weight: normal;
    cursor: pointer;
}
    </style>

I mix the solutions of many developers and reach to this solution.
It change the original array list after deletion which means if we want to save the images then we can do so.

<script>
    var images = [];
      function image_select() {
          var image = document.getElementById('image').files;
          for (i = 0; i < image.length; i++) {
            images.push({
                "name" : image[i].name,
                "url" : URL.createObjectURL(image[i]),
                "file" : image[i],
            })
          }
          document.getElementById('container').innerHTML = image_show();
      }

      function image_show() {
          var image = "";
          images.forEach((i) => {
             image += `<div class="image_container d-flex justify-content-center position-relative">
                  <img src="`+ i.url +`" alt="Image">
                  <span class="position-absolute" onclick="delete_image(`+ images.indexOf(i) +`)">×</span>
              </div>`;
          })
          return image;
      }
      function delete_image(e) {
        images.splice(e, 1);
        document.getElementById('container').innerHTML = image_show();

        const dt = new DataTransfer()
        const input = document.getElementById('image')
        const { files } = input

        for (let i = 0; i < files.length; i++) {
            const file = files[i]
            if (e !== i)
            dt.items.add(file);
        }

        input.files = dt.files;
        console.log(document.getElementById('image').files);
      }
</script>

*******This is html code ******

<body>
    <div class="container mt-3 w-100">
        <div class="card shadow-sm w-100">
            <div class="card-header d-flex justify-content-between">
                <h4>Preview Multiple Images</h4>
                <form class="form" action="{{route('store')}}" method="post" id="form" enctype="multipart/form-data">
                    @csrf
                    <input type="file" name="image[]" id="image" multiple onchange="image_select()">
                    <button class="btn btn-sm btn-primary" type="submit">Submit</button>
                </form>
            </div>
            <div class="card-body d-flex flex-wrap justify-content-start" id="container">

            </div>
        </div>
    </div>
</body>

******* This is CSS code ********

<style>
        .image_container {
    height: 120px;
    width: 200px;
    border-radius: 6px;
    overflow: hidden;
    margin: 10px;
}
.image_container img {
    height: 100%;
    width: auto;
    object-fit: cover;
}
.image_container span {
    top: -6px;
    right: 8px;
    color: red;
    font-size: 28px;
    font-weight: normal;
    cursor: pointer;
}
    </style>
無心 2024-09-14 08:45:54

我正在使用 TypeScript,但由于强类型检查,它在每一步都会抱怨。以下代码在 Svelte 中对我有用。它与斯维尔特无关。所以它应该适用于所有使用 TS 的库/框架。

const ele = document.getElementById('file-upload') as HTMLInputElement;
if (ele) {
    ele.value = "";
}

I am using TypeScript and it complained at every steps because of strong type checking. The following code worked for me in Svelte. It has nothing to do with Svelte. So it should work with all libraries/frameworks using TS.

const ele = document.getElementById('file-upload') as HTMLInputElement;
if (ele) {
    ele.value = "";
}
梨涡少年 2024-09-14 08:45:54
 function removeFile(idx: number) {

    if (files) { 
      let fileArr = Array.from(files)
      fileArr.splice(idx, 1)
      let tempObj: any = Object.assign({ length: fileArr.length }, fileArr)
      console.log(tempObj);
      setfiles(tempObj);
    }

  }
 function removeFile(idx: number) {

    if (files) { 
      let fileArr = Array.from(files)
      fileArr.splice(idx, 1)
      let tempObj: any = Object.assign({ length: fileArr.length }, fileArr)
      console.log(tempObj);
      setfiles(tempObj);
    }

  }
帅冕 2024-09-14 08:45:54

显然,到 2024 年,这仍然是一件不太明显的事情。真正修改 input.files 列表的唯一方法似乎是将其替换为 DataTransfer.files最佳答案所示。

这是几乎相同的代码,但使用 Array.reduce 编写:

function removeFile(input, index) {
  input.files = [...input.files]
    .reduce((dt, f, i) => {
      if(i !== index) {
        dt.items.add(f);
      }
      return dt;
    }, new DataTransfer())
    .files;
}

这是代码的更简洁版本,但有点难以理解:

function removeFile(input, index) {
  input.files = [...input.files]
    .reduce((dt, f, i) => (i !== index && dt.items.add(f) && 0) || dt, new DataTransfer())
    .files;
}

Apparently this is still a not-so-obvious thing in 2024. The only way to truly modify the input.files list seems to be by replacing it with a DataTransfer.files as demonstrated in the best answer.

Here is pretty much the same code but written using Array.reduce:

function removeFile(input, index) {
  input.files = [...input.files]
    .reduce((dt, f, i) => {
      if(i !== index) {
        dt.items.add(f);
      }
      return dt;
    }, new DataTransfer())
    .files;
}

Here is a more concise version of the code but a bit harder to grasp:

function removeFile(input, index) {
  input.files = [...input.files]
    .reduce((dt, f, i) => (i !== index && dt.items.add(f) && 0) || dt, new DataTransfer())
    .files;
}
何其悲哀 2024-09-14 08:45:54

您可能希望创建一个数组并使用它来代替只读文件列表。

var myReadWriteList = new Array();
// user selects files later...
// then as soon as convenient... 
myReadWriteList = FileListReadOnly;

之后,根据您的列表而不是内置列表进行上传。我不确定您正在使用的上下文,但我正在使用我发现的 jquery 插件,我要做的就是获取插件的源代码并使用

然后只需更换参考文献即可。

我认为这还可以让您添加拖动和拖动功能。再次删除,如果内置列表是只读的,那么您还能如何将删除的文件放入列表中?

:))

You may wish to create an array and use that instead of the read-only filelist.

var myReadWriteList = new Array();
// user selects files later...
// then as soon as convenient... 
myReadWriteList = FileListReadOnly;

After that point do your uploading against your list instead of the built in list. I am not sure of the context you are working in but I am working with a jquery plugin I found and what I had to do was take the plugin's source and put it in the page using <script> tags. Then above the source I added my array so that it can act as a global variable and the plugin could reference it.

Then it was just a matter of swapping out the references.

I think this would allow you to also add drag & drop as again, if the built in list is read-only then how else could you get the dropped files into the list?

:))

焚却相思 2024-09-14 08:45:54

我这样解决

 //position  -> the position of the file you need to delete

  this.fileImgs.forEach((item, index, object) => {
     if(item.idColor === idC){
        if(item.imgs.length === 1){
            object.splice(index,1) }
        else{
           const itemFileImgs = [...item.imgs];
           itemFileImgs.splice(position,1)
           item.imgs = [...itemFileImgs] 
            }
        }});
      console.log(this.fileImgs)

在此处输入图像描述

I solve it this way

 //position  -> the position of the file you need to delete

  this.fileImgs.forEach((item, index, object) => {
     if(item.idColor === idC){
        if(item.imgs.length === 1){
            object.splice(index,1) }
        else{
           const itemFileImgs = [...item.imgs];
           itemFileImgs.splice(position,1)
           item.imgs = [...itemFileImgs] 
            }
        }});
      console.log(this.fileImgs)

enter image description here

飘然心甜 2024-09-14 08:45:54

在 vue.js 中:

self.$refs.inputFile.value = ''

In vue js :

self.$refs.inputFile.value = ''

久伴你 2024-09-14 08:45:54

我只是将输入类型更改为文本并返回到文件:D

I just change the type of input to the text and back to the file :D

内心激荡 2024-09-14 08:45:53

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

HTMLInputElement 界面
[HTML5] 有一个只读 FileList
属性,[...]
[强调我的]

阅读了一些 HTML 5 工作草案,我发现了 通用input元素API。看来您可以通过将 input 对象的 value 属性设置为空字符串来删除整个文件列表,例如:

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

顺便说一句,文章使用网络应用程序中的文件也可能令人感兴趣。

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

The HTMLInputElement interface
[HTML5] has a readonly FileList
attribute, […]
[emphasis mine]

Reading a bit of the HTML 5 Working Draft, I came across the Common input element APIs. It appears you can delete the entire file list by setting the value property of the input object to an empty string, like:

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

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

丢了幸福的猪 2024-09-14 08:45:53

由于 JavaScript FileList 是只读的,无法直接操作,

最佳方法

您必须循环遍历 input.files,同时将其与 index 进行比较您要删除的文件的名称。同时,您将使用new DataTransfer()设置一个新的文件列表,不包括要从文件列表中删除的文件。

通过这种方法,input.files 本身的值会发生变化。

removeFileFromFileList(index) {
  const dt = new DataTransfer();
  const input = document.getElementById('files');
  const { files } = input;
  
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    if (index !== i) {
      dt.items.add(file); // here you exclude the file. thus removing it.
    }
  }
  
  /* Assigning data transfer object files to the 'input' variable will not write the data transfer files to it because it doesn't have the reference to the element: Instead write, */
  document.getElementById('files') = dt.files; // Assign the updates list
}

替代方法

另一种简单的方法是将FileList转为数组,然后拼接。

但这种方法不会改变 input.files

const input = document.getElementById('files');
// as an array, u have more freedom to transform the file list using array functions.
const fileListArr = Array.from(input.files);
fileListArr.splice(index, 1); // here u remove the file
console.log(fileListArr);

Since JavaScript FileList is readonly and cannot be manipulated directly,

BEST METHOD

You will have to loop through the input.files while comparing it with the index of the file you want to remove. At the same time, you will use new DataTransfer() to set a new list of files excluding the file you want to remove from the file list.

With this approach, the value of the input.files itself is changed.

removeFileFromFileList(index) {
  const dt = new DataTransfer();
  const input = document.getElementById('files');
  const { files } = input;
  
  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    if (index !== i) {
      dt.items.add(file); // here you exclude the file. thus removing it.
    }
  }
  
  /* Assigning data transfer object files to the 'input' variable will not write the data transfer files to it because it doesn't have the reference to the element: Instead write, */
  document.getElementById('files') = dt.files; // Assign the updates list
}

ALTERNATIVE METHOD

Another simple method is to convert the FileList into an array and then splice it.

But this approach will not change the input.files

const input = document.getElementById('files');
// as an array, u have more freedom to transform the file list using array functions.
const fileListArr = Array.from(input.files);
fileListArr.splice(index, 1); // here u remove the file
console.log(fileListArr);
吻泪 2024-09-14 08:45:53

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

将 FileList 视为数组会很方便,但排序、移位、弹出和切片等方法不起作用。正如其他人所建议的,您可以将 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;
 });

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

This question has already been marked answered, but I'd like to share some information that might help others with using 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.

 // 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+

放我走吧 2024-09-14 08:45:53

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

let fileArray = Array.from(fileList);

然后就可以像处理任何其他数组一样轻松处理 File 数组。

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:

let fileArray = Array.from(fileList);

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

赤濁 2024-09-14 08:45:53

由于我们处于 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."));

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.

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."));
聆听风音 2024-09-14 08:45:53

我发现很快&对此的简短解决方法。在许多流行的浏览器(Chrome、Firefox、Safari)中进行了测试;

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

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

才能使用此删除特定元素

newFileList.splice(index,1);

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

First, you have to convert FileList to an Array

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

to delete the particular element use this

newFileList.splice(index,1);
萌梦深 2024-09-14 08:45:53

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

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

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

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

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

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

人生百味 2024-09-14 08:45:53

这是临时的,但我遇到了同样的问题,我用这种方式解决了。就我而言,我是通过 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;
    }
};

现在是这个的 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>

那种风​​格。我必须标记其中一些!重要的是要覆盖 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;
}

我希望这有帮助。

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.

// 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.

<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.

.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.

半枫 2024-09-14 08:45:53

感谢@Nicholas Anderson 简单而直接,这是您应用的代码并使用 jquery 在我的代码中工作。

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代码

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

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

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);
}
风情万种。 2024-09-14 08:45:53

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

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

基本上你可以获取输入的值。克隆它并将克隆代替旧的。

There might be a more elegant way to do this but here is my solution. With 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.

蒲公英的约定 2024-09-14 08:45:53

如果您有幸向数据库发送带有文件的 post 请求,并且您的 DOM 中有要发送的文件,

您可以简单地检查文件列表中的文件是否存在于您的 DOM 中,当然如果并不是您只是不将该元素发送到数据库。

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

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.

栩栩如生 2024-09-14 08:45:53

我意识到这是一个相当老的问题,但是我正在使用 html 多文件选择上传来对任意数量的文件进行排队,这些文件可以在提交之前在自定义 UI 中有选择地删除。

将文件保存在如下变量中:

let uploadedFiles = [];

//inside DOM file select "onChange" event
let selected = e.target.files[0] ? e.target.files : [];
uploadedFiles = [...uploadedFiles , ...selected ];
createElements();

使用“删除文件”创建 UI:

function createElements(){
  uploadedFiles.forEach((f,i) => {

    //remove DOM elements and re-create them here
    /* //you can show an image like this:
    *  let reader = new FileReader();
    *  reader.onload = function (e) {
    *    let url = e.target.result;
    *    // create <img src=url />
    *  };
    *  reader.readAsDataURL(f);
    */

    element.addEventListener("click", function () {
      uploadedFiles.splice(i, 1);
      createElements();
    });

  }
}

提交到服务器:

let fd = new FormData();
uploadedFiles.forEach((f, i) => {
  fd.append("files[]", f);
});
fetch("yourEndpoint", { 
  method: "POST", 
  body: fd, 
  headers: { 
    //do not set Content-Type 
  } 
}).then(...)

I realize this is a pretty old question, however I am using an html multiple file selection upload to queue any number of files which can be selectively removed in a custom UI before submitting.

Save files in a variable like this:

let uploadedFiles = [];

//inside DOM file select "onChange" event
let selected = e.target.files[0] ? e.target.files : [];
uploadedFiles = [...uploadedFiles , ...selected ];
createElements();

Create UI with "remove a file":

function createElements(){
  uploadedFiles.forEach((f,i) => {

    //remove DOM elements and re-create them here
    /* //you can show an image like this:
    *  let reader = new FileReader();
    *  reader.onload = function (e) {
    *    let url = e.target.result;
    *    // create <img src=url />
    *  };
    *  reader.readAsDataURL(f);
    */

    element.addEventListener("click", function () {
      uploadedFiles.splice(i, 1);
      createElements();
    });

  }
}

Submit to server:

let fd = new FormData();
uploadedFiles.forEach((f, i) => {
  fd.append("files[]", f);
});
fetch("yourEndpoint", { 
  method: "POST", 
  body: fd, 
  headers: { 
    //do not set Content-Type 
  } 
}).then(...)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文