Dosya Listesinden bir dosyayı nasıl kaldırırım


111

HTML5 kullanarak yüklemek için sürükle ve bırak web uygulaması oluşturuyorum ve dosyaları bir div üzerine bırakıyorum ve tabii ki bana FileList'i veren dataTransfer nesnesini getiriyorum .

Şimdi bazı dosyaları kaldırmak istiyorum, ancak nasıl yapılacağını veya mümkün olup olmadığını bilmiyorum.

Tercihen onları DosyaListesinden silmek istiyorum; Onlara ihtiyacım yok. Ancak bu mümkün değilse, bunun yerine çekleri DosyaListesi ile etkileşime giren kodda yazmalı mıyım? Bu külfetli görünüyor.


Sadece merak ediyorum: neden bunu yapmak istiyorsun? Kullanıcının seçtiği (bazı) dosyalar için neden “Onları kullanmıyorum” diyorsunuz?
Marcel Korpel

24
Muhtemelen daha çok, kullanıcının yüklemeden önce dosyaları kaldırabilmesi içindir. Başlangıçta 20'yi seçtiyseniz ve sonra 14'ünü yüklemek istemediğinize karar verirseniz, o zaman onu kaldıramazsınız, her şeye yeniden başlamanız gerekir (bu biraz acı verici). Bence FileList'i salt okunur yapmak, görmediğim bazı güvenlik sonuçları olmadıkça kötü bir gözetim.
Rafael

Dosyaları doğrudan girişin Dosya
Listesinden silmekle

Yanıtlar:


150

Seçili dosyalardan yalnızca birkaçını silmek istiyorsanız: yapamazsınız. Bağlandığınız Dosya API Çalışma Taslağı bir not içerir:

HTMLInputElementArayüz [HTML5] Bir sahiptir salt okunur FileList özniteliği, [...]
[vurgu benim]

HTML 5 Çalışma Taslağının bir kısmını okurken, Common inputelement API'lerine rastladım . Görünüşe göre, nesnenin özelliğini boş bir dizeye ayarlayarak tüm dosya listesini silebilirsiniz , örneğin:valueinput

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

BTW, Web uygulamalarından dosyaların kullanılması makalesi de ilgi çekici olabilir.


1
Bir niteliğin salt okunur olmasının, işaret ettiği nesneyi değiştiremeyeceğiniz anlamına gelmediğini unutmayın . FileList'i değiştirebilirsiniz (eğer bu mümkünse), bu sadece ona yeni bir FileList atayamayacağınız anlamına gelir.
Robin Berjon

1
@RobinBerjon Chrome, FireFox yazma işlemlerine izin vermezken "readonly" özelliğini yok sayıyor gibi görünüyor. Ne yazık ki sadece FileList'i değiştirme öneriniz FireFox'ta da çalışmıyor.
borisdiakur

1
Sadece lengthsalt okunur olduğunu düşünüyorum. Eklemeli bir öğeyi silmeye çalışıyorum, Chrome'da başarısız oluyor.
zhiyelee

Eklemenin bir yolu var mı?
streetlight

1
@streetlight Site sahibi bir kullanıcının makinesinden hangi dosyaların yükleneceğini belirleyebilirse, bu büyük bir güvenlik açığı olur.
Marcel Korpel

30

Bu soru zaten yanıtlanmış olarak işaretlendi, ancak FileList'i kullanarak başkalarına yardımcı olabilecek bazı bilgileri paylaşmak istiyorum.

Bir FileList'i bir dizi olarak ele almak uygun olur, ancak sort, shift, pop ve slice gibi yöntemler çalışmaz. Diğerlerinin önerdiği gibi, FileList'i bir diziye kopyalayabilirsiniz. Bununla birlikte, bir döngü kullanmak yerine, bu dönüşümü gerçekleştirmek için basit bir tek satırlık çözüm vardır.

 // 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 ve IE10 + 'da test edildi


4
Array.from(fileDialog.files)daha basit
Muhammad Umer

1
@Muhammad Umer - Teşekkürler, daha basit olduğunu ve alternatif bir cevap olarak listelendiğini kabul ediyorum. Yine de, hangi tarayıcıların desteklenmesi gerektiğine ve Array.from () kullanmak için bir pollyfill gerekip gerekmediğine bağlıdır. Bakınız: stackoverflow.com/a/36810954/943435
Roberto

Dosya Listesini gerçekte nasıl değiştirirsiniz? Bu yeni dizi girdiye atansın fileDialog.files = fileBuffer mı?
eozzy

@ 3zzy - FileList'i değiştirmek mümkündür, ancak yalnızca modern tarayıcılarda. Ayrıntılar için bu SO sorularına bakın: stackoverflow.com/a/47522812/943435
Roberto

22

Evergreen tarayıcıları (Chrome, Firefox, Edge, ancak Safari 9+ ile de çalışıyor) hedefliyorsanız veya bir çoklu dolguyu karşılayabiliyorsanız, aşağıdaki Array.from()gibi kullanarak FileList'i bir diziye dönüştürebilirsiniz :

let fileArray = Array.from(fileList);

O zaman Fileherhangi bir dizi gibi diziyi kullanmak kolaydır .


Mükemmel! IE desteğinin nasıl olduğunu biliyor musunuz? Ya da belki bir çoklu dolgunun bağlantısını paylaşabilirsiniz?
Serhii Matrunchyk


Sadece idare sağlayacak fileArraydeğil fileList.
VipinKundal

12

HTML5 alanında olduğumuz için bu benim çözümüm. İşin özü, dosyaları bir FileList içinde bırakmak yerine bir Diziye itmeniz, ardından XHR2 kullanarak dosyaları bir FormData nesnesine göndermenizdir. Aşağıdaki örnek.

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."));

ajax tek yol o zaman sanırım?
Muhammad Umer

10

Bunun için çok hızlı ve kısa bir çözüm buldum. Birçok popüler tarayıcıda (Chrome, Firefox, Safari) test edilmiştir;

Öncelikle, FileList'i bir Array'e dönüştürmelisiniz.

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

belirli bir öğeyi silmek için bunu kullanın

newFileList.splice(index,1);

12
event.target.filesGirişe bağlı olmayan yeni değişken yarattınız, bu yüzden yerel değişkeniniz dışında hiçbir şeyi değiştiremez ..
Maksims Kitajevs

6

Bunun eski bir soru olduğunu biliyorum ama bu konuyla ilgili olarak arama motorlarında üst sıralarda yer alıyor.

FileList nesnesindeki özellikler silinemez, ancak en azından Firefox'ta değiştirilebilirler . Bu sorunun geçici çözümü IsValid=true, denetimden geçen dosyalara bir özellik eklemekti veIsValid=false geçmeyen .

daha sonra FormData'ya yalnızca özellikli özelliklerin IsValid=trueeklendiğinden emin olmak için listeden geçiyorum .


formdata, yani onları ajax aracılığıyla mı gönderiyorsunuz?
Muhammad Umer

1

Bunu yapmanın daha zarif bir yolu olabilir ama işte benim çözümüm. Jquery ile

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

Temel olarak girdinin değerini temizlersiniz. Klonlayın ve klonu eskisinin yerine koyun.


1

Bu çok geçicidir, ancak bu şekilde çözdüğüm sorunun aynısını yaşadım. Benim durumumda dosyaları XMLHttp isteği ile yüklüyordum, bu yüzden klonlanmış FileList verilerini formdata ekleyerek gönderebildim. İşlevsellik, birden çok dosyayı istediğiniz kadar sürükleyip bırakabilmeniz veya seçebilmenizdir (dosyaları tekrar seçmek klonlanan Dosya Listesini sıfırlamaz), (klonlanmış) dosya listesinden istediğiniz herhangi bir dosyayı kaldırabilir ve xmlhttprequest ile gönderebilirsiniz. Oradan ayrıldı. Ben öyle yaptım. Buradaki ilk yazım bu yüzden kod biraz dağınık. Afedersiniz. Ah, ve Joomla betiğinde olduğu gibi $ yerine jQuery kullanmak zorunda kaldım.

// 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;
    }
};

Şimdi bunun için html ve stiller. Oldukça acemiyim ama tüm bunlar aslında benim için çalıştı ve anlamam biraz zaman aldı.

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

Bunun için stiller. Joomla davranışını geçersiz kılmak için bazılarını işaretlemeliydim!

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

Umarım bu yardımcı olur.


1

Teşekkürler @Nicholas Anderson basit ve açık, işte kodunuz uygulandı ve jquery kullanarak kodumda çalışıyor.

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 KODU

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


0

Veritabanına dosyalarla birlikte bir gönderi isteği gönderme şansınız varsa ve göndermek istediğiniz dosyalar DOM'nuzda mevcutsa

Dosya listesindeki dosyanın DOM'nuzda bulunup bulunmadığını kontrol edebilirsiniz ve elbette bu siz değilseniz, bu öğeyi de DB'ye göndermeyin.


-1

Salt okunur dosya listesi yerine bir dizi oluşturup bunu kullanmak isteyebilirsiniz.

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

Bu noktadan sonra yüklemenizi yerleşik liste yerine kendi listenize karşı yapın. İçinde çalıştığınız bağlamdan emin değilim, ancak bulduğum bir jquery eklentisiyle çalışıyorum ve yapmam gereken, eklentinin kaynağını alıp sayfaya koymaktı.<script> etiketleri . Sonra kaynağın üstüne dizimi ekledim, böylece küresel bir değişken olarak davranabilir ve eklenti ona başvurabilir.

O zaman mesele referansları değiştirmekti.

Bence bu, eğer yerleşik liste salt okunursa, bırakılan dosyaları başka nasıl listeye alabilirsin?

:))


4
Çok erken yazdım .... bir değişkeni dosya listesine eşit olarak ayarladığı anda salt okunur sorunu geri geliyor ... Böylece yapmayı seçtiğim şey iki kat ve biraz acı verici ama etkili ... Yüklenecek dosyaların görünür bir listesi ve buradan kullanıcı kaldırabilir ... açıkça bir <ul> etiketindeki <li> etiketini kaldırmak basittir ... bu yüzden bulduğum tek yöntem ikincil bir liste tutmaktır kaldırılan dosyalardan birini seçin ve yükleme işlemi sırasında ona bakın ... bu nedenle dosya yükleme listesindeyse, atlarım ve kullanıcı daha akıllı değil.
cary abramoff

FileListNesneyi myReadWriteListdeğişkene atadığınızda, türünden olarak Arraydeğiştirilir FileList, dolayısıyla bu bir çözüm değildir.
adlr0

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.