bırakma dosyalarını standart html dosya girişine sürükleyin


163

Bu günlerde dosyaları özel bir kap içine sürükleyip bırakabilir ve XHR 2 ile yükleyebiliriz. Canlı ilerleme çubukları vb ile. Çok güzel şeyler.Burada örnek.

Ama bazen bu kadar serinlik istemiyoruz. Ne istiyorum - bir kerede birçok - dosyaları standart bir HTML dosya girişine sürükleyip bırakmak :<input type=file multiple> .

Mümkün mü? Dosya girişini, dosya damlasından doğru dosya adları (?) İle doldurmanın bir yolu var mı? (Dosya sistemi güvenliği nedeniyle tam dosya yolları kullanılamaz.)

Neden? Çünkü normal bir form göndermek istiyorum. Tüm tarayıcılar ve tüm cihazlar için. Sürükle ve bırak özelliği, UX'i geliştirmek ve basitleştirmek için aşamalı bir geliştirmedir. Standart dosya girişi (+ multipleözniteliği) olan standart form orada olacaktır. HTML5 geliştirmesini eklemek istiyorum.

düzenlemek
ben biliyorum bazı tarayıcılarda yapabilirsiniz bazen (hemen hemen her zaman) dosyası girişine kendisi içine dosyalar açılır. Chrome'un genellikle bunu yaptığını biliyorum, ancak bazen başarısız oluyor ve ardından dosyayı geçerli sayfaya yüklüyor (bir formu doldurursanız büyük bir başarısızlık). Bunu kandırmak istiyorum.


1
Uyumluluklarınıza mac / safari eklemek istiyorsanız biraz acı için hazırlanın.
Shark8

1
@ Shark8 aslında Safari / Mac bunu zaten destekleyen birkaç tarayıcıdan biridir.
Ricardo Tomasi

Aslında, tarayıcıların hiçbiri bunu desteklemiyor. Dosya giriş alanı salt okunurdur (güvenlik için) ve sorun budur. Aptal güvenlik!
Rudie

2
By bu i "- Bir anda birçok - standart bir HTML dosyası girişine sürükle & bırak dosyaları" anlamına geliyordu.
Ricardo Tomasi

3
input type="file" multipleSafari'de iyi çalışmak için birden çok dosyayı sürükleyip bırakın
Lloyd

Yanıtlar:


71

Aşağıdaki Chrome ve FF'de çalışıyor, ancak henüz IE10 + 'ı da kapsayan bir çözüm bulamadım:

// dragover and dragenter events need to have 'preventDefault' called
// in order for the 'drop' event to register. 
// See: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations#droptargets
dropContainer.ondragover = dropContainer.ondragenter = function(evt) {
  evt.preventDefault();
};

dropContainer.ondrop = function(evt) {
  // pretty simple -- but not for IE :(
  fileInput.files = evt.dataTransfer.files;

  // If you want to use some of the dropped files
  const dT = new DataTransfer();
  dT.items.add(evt.dataTransfer.files[0]);
  dT.items.add(evt.dataTransfer.files[3]);
  fileInput.files = dT.files;

  evt.preventDefault();
};
<!DOCTYPE html>
<html>
<body>
<div id="dropContainer" style="border:1px solid black;height:100px;">
   Drop Here
</div>
  Should update here:
  <input type="file" id="fileInput" />
</body>
</html>

addEventListenerEvt işleyicilerinizi kaydetmek için muhtemelen veya jQuery (vb.) Kullanmak isteyeceksiniz - bu sadece kısaca aşk içindir.


3
Waaaaaaaat! Bu işe yarıyor!? Tam da aradığım şey buydu . 2 yıl önce çalışmadı. Müthiş! Tabii ki IE'de çalışmıyor =) Önemli soru: güvenilir özellik tespiti var mı?, Böylece IE'de dropzone gizleyebilirsiniz, bc çalışmaz.
Rudie

D'oh, biraz geç sonra :) Şu anda im sadece JS basit kullanıcı aracısı çekleri kullanarak im. Tabii ki MSIE , Trident/(IE11) ve Edge/(IE12) için test etmek zorundasınız ...
jlb

FF 48.0.2 (Mac), "TypeError: yalnızca alıcısı olan bir özelliği ayarlama" satırına atıyor fileInput.files = evt.dataTransfer.files;. Ancak Safari ve Chrome iyi çalışıyor.
Risadinha

2
Bu örnek linux üzerinde firefox 45 üzerinde çalışmıyor, ancak benim için krom üzerinde çalışıyor. Herhangi bir konsol hatası almıyorum, herhangi bir dosyanın düşürüldüğünü göstermiyor.
Bryan Oakley

1
aslında bir çözüm bulup denemek için bir yazı yaptım ama kendim anladım. Oldukça basit bir değişiklik, sadece dosya verilerini belirli bir girişe geçirmek için fileInputs [index] = ... ve sonra yeni bir giriş eklemek için showNext işlevini çağırmak stackoverflow.com/a/43397640/6392779
nick

51

Bunun için bir çözüm buldum.

Bu yöntemin Sürükle ve Bırak işlevi yalnızca Chrome, Firefox ve Safari ile çalışır. (IE10 ile çalışıp çalışmadığını bilmiyorum), ancak diğer tarayıcılarda "Veya burayı tıklayın" düğmesi iyi çalışır.

Bir alanın üzerine bir dosya sürüklerken giriş alanı sadece farenizi takip edin ve ben de bir düğme ekledim ..

Rahatsızlık opaklığı: 0; dosya girdisi yalnızca görülebilir, böylece neler olduğunu görebilirsiniz.


Bu yüzden ben de bir düğme ekledim ^^ Ama yah haklısın. Tüy kullanmam ... Yoksa ister miydim?
BjarkeCK

Keşke bunun nasıl çalışması gerektiğini biliyor olsaydım ... tüm sürükle / bırak işlevlerinin fareyle üzerine gelme efekti eklemekle uğraşması gerektiği anlaşılıyor ... ama gerçekten söyleyemem. Kemanda iyi görünüyor, ancak Internet Explorer'ı desteklemem gerektiğinden kullanabileceğimi sanmıyorum
nmz787

1
@PiotrKowalski Bence bu çağrı yığını taşana kadar özyinelemeli bir çağrıyı tetikler
John

2
Ben sadece tarzı kullanarak sona erdi. Girişin% 100 genişlik ve yükseklikte hareket ettirilmesi, onu hareket ettirmekten daha iyi yaptı.
Eddie

2
Fare işaretçimizle birlikte gezinmeye devam eden "dosya seçilmedi" den kurtulmanın bir yolu var mı? BjarkeCK
Abhishek Singh

27

Bunu yapmanın "DTHML" HTML5 yoludur. Normal form girişi (IS yalnızca Ricardo Tomasi'nin işaret ettiği gibi okunur). Sonra bir dosya sürüklenirse, forma eklenir. Bu, bu şekilde yüklenen dosyayı kabul etmek için eylem sayfasında değişiklik yapılmasını gerektirecektir.

function readfiles(files) {
  for (var i = 0; i < files.length; i++) {
    document.getElementById('fileDragName').value = files[i].name
    document.getElementById('fileDragSize').value = files[i].size
    document.getElementById('fileDragType').value = files[i].type
    reader = new FileReader();
    reader.onload = function(event) {
      document.getElementById('fileDragData').value = event.target.result;}
    reader.readAsDataURL(files[i]);
  }
}
var holder = document.getElementById('holder');
holder.ondragover = function () { this.className = 'hover'; return false; };
holder.ondragend = function () { this.className = ''; return false; };
holder.ondrop = function (e) {
  this.className = '';
  e.preventDefault();
  readfiles(e.dataTransfer.files);
}
#holder.hover { border: 10px dashed #0c0 !important; }
<form method="post" action="http://example.com/">
  <input type="file"><input id="fileDragName"><input id="fileDragSize"><input id="fileDragType"><input id="fileDragData">
  <div id="holder" style="width:200px; height:200px; border: 10px dashed #ccc"></div>
</form>

Tüm pencereyi bir bırakma bölgesi yapabilirseniz daha da patron olur, bkz. Gmail'in yaptığı gibi pencereye giren ve pencereden çıkan bir HTML5 sürükleme olayını nasıl algılayabilirim?


1
İyi bir çözüm henüz IE <10 üzerinde çalışmıyor çünkü IE 9 ve daha azı HTML5 dosyalarını desteklemiyor API :(
Develoger

1
Bu satır: document.getElementById ('fileDragData'). Value = dosya [i] .slice (); gerekli değildir, çünkü bu, reader.onload fonksiyonunun yerini almıştır
kurdtpage

İşte dosya yüklemelerini içermeyen başka bir sevimli sürükle ve bırak uygulaması. Birisi daha fazla çalışmak istiyorsa bağlantı kurmak. codepen.io/anon/pen/MOPvZK?editors=1010
William Entriken

1
IE 10 çözümü bozulmak ve sadece göstermekinput type=file
William Entriken

Bir şeyi mi kaçırıyorum, yoksa .valueön döngüde her yinelediğinizde, sürekli olarak en son dosyayla mülkün üzerine mi yazıyorsunuz?
Kevin Burke

13

//----------App.js---------------------//
$(document).ready(function() {
    var holder = document.getElementById('holder');
    holder.ondragover = function () { this.className = 'hover'; return false; };
    holder.ondrop = function (e) {
      this.className = 'hidden';
      e.preventDefault();
      var file = e.dataTransfer.files[0];
      var reader = new FileReader();
      reader.onload = function (event) {
          document.getElementById('image_droped').className='visible'
          $('#image_droped').attr('src', event.target.result);
      }
      reader.readAsDataURL(file);
    };
});
.holder_default {
    width:500px; 
    height:150px; 
    border: 3px dashed #ccc;
}

#holder.hover { 
    width:400px; 
    height:150px; 
    border: 3px dashed #0c0 !important; 
}

.hidden {
    visibility: hidden;
}

.visible {
    visibility: visible;
}
<!DOCTYPE html>

<html>
    <head>
        <title> HTML 5 </title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
    </head>
    <body>
      <form method="post" action="http://example.com/">
        <div id="holder" style="" id="holder" class="holder_default">
          <img src="" id="image_droped" width="200" style="border: 3px dashed #7A97FC;" class=" hidden"/>
        </div>
      </form>
    </body>
</html>


2
Kullanıcıya ne gösteriyor? Bir keman veya çevrimiçi örnek yapabilir misiniz?
Rudie

@Rudie tıklayın kod snippet'i çalıştırın ve görüntülemek için bir resmi sürükleyip-bırakın-bırakın, düştü görüntünün önizleme gösterecektir.
Dipak

6

Teorik olarak, öğesinin üzerine bindirilen bir öğe ekleyebilir <input/>ve daha sonra, dropolayları dosyaları yakalamak için (Dosya API'sını kullanarak) kullanabilir ve bunları girdi filesdizisine iletebilirsiniz .

Bir dosya girişinin salt okunur olması dışında . Bu eski bir problem.

Bununla birlikte, form denetimini tamamen atlayabilir ve XHR aracılığıyla yükleyebilirsiniz (bunun için destek konusunda emin değilsiniz):

Ayrıca, Chrome'daki drop olayını iptal etmek ve dosyanın varsayılan yükleme davranışını önlemek için çevredeki bir öğeyi kullanabilirsiniz.

Birden çok dosyayı girişin üzerine bırakmak Safari ve Firefox'ta zaten çalışıyor.


6
Soruda söylediğim gibi: XHR2'yi biliyorum ve kullanmak istemiyorum. Önemsiz kısmı sanırım: "dosya girişi salt okunur". Bu berbat ... Bırakma olayını iptal etmek kötü bir fikir değil! Umduğum kadar iyi değil, ama muhtemelen en iyisi. Birden fazla dosyayı bırakmak Chrome'da da çalışır. Chrome artık dizinlerin yüklenmesine de izin veriyor. Hepsi çok kewl ve benim durumuma yardım değil = (
Rudie

5

Ben de bunu çıkardım.

Jquery ve Html kullanma. Bu, ekleme dosyalarına ekleyecektir.

var dropzone = $('#dropzone')


dropzone.on('drag dragstart dragend dragover dragenter dragleave drop', function(e) {
    e.preventDefault();
    e.stopPropagation();
  })

dropzone.on('dragover dragenter', function() {
    $(this).addClass('is-dragover');
  })
dropzone.on('dragleave dragend drop', function() {
    $(this).removeClass('is-dragover');
  })  
  
dropzone.on('drop',function(e) {
	var files = e.originalEvent.dataTransfer.files;
	// Now select your file upload field 
	// $('input_field_file').prop('files',files)
  });
input {	margin: 15px 10px !important;}

.dropzone {
	padding: 50px;
	border: 2px dashed #060;
}

.dropzone.is-dragover {
  background-color: #e6ecef;
}

.dragover {
	bg-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class="" draggable='true' style='padding: 20px'>
	<div id='dropzone' class='dropzone'>
		Drop Your File Here
	</div>
	</div>


4

Yalnızca CSS çözümü için:

<div class="file-area">
    <input type="file">
    <div class="file-dummy">
        <span class="default">Click to select a file, or drag it here</span>
        <span class="success">Great, your file is selected</span>
    </div>
</div>

.file-area {
    width: 100%;
    position: relative;
    font-size: 18px;
}
.file-area input[type=file] {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    opacity: 0;
    cursor: pointer;
}
.file-area .file-dummy {
    width: 100%;
    padding: 50px 30px;
    border: 2px dashed #ccc;
    background-color: #fff;
    text-align: center;
    transition: background 0.3s ease-in-out;
}
.file-area .file-dummy .success {
    display: none;
}
.file-area:hover .file-dummy {
    border: 2px dashed #1abc9c;
}
.file-area input[type=file]:valid + .file-dummy {
    border-color: #1abc9c;
}
.file-area input[type=file]:valid + .file-dummy .success {
    display: inline-block;
}
.file-area input[type=file]:valid + .file-dummy .default {
    display: none;
}

Https://codepen.io/Scribblerockerz/pen/qdWzJw adresinden değiştirildi


4

Chrome'da bazı hile çalışmalarını biliyorum:

Dosyaları bırakma bölgesine dataTransfer.filesbıraktığınızda, FileListsürüklediğiniz tüm dosyaları içeren bir nesne, yani bir nesne türü alırsınız. Bu arada, <input type="file" />elemanın özelliği filesaynı FileListtip nesnedir.

Böylece, dataTransfer.filesnesneyi input.filesözelliğe atayabilirsiniz .


3
Evet, bugünlerde öyle. Bir numara değil. Çok kasıtlı. Ayrıca çok kasıtlı olarak çok kısıtlı. Listeye dosya ekleyemez veya listeyi hiç değiştiremezsiniz. Sürükleme ve bırakma dosyaları hatırlayabilir ve ekleyebilir, ancak input.files= =
Rudie

3

2018'de bunu yapmak isteyen herkes için, burada yayınlanan tüm eski şeylerden çok daha iyi ve daha basit bir çözümüm var. Sadece vanilya HTML, JavaScript ve CSS ile hoş görünümlü bir sürükle ve bırak kutusu yapabilirsiniz.

(Şimdiye kadar yalnızca Chrome'da çalışıyor)

HTML ile başlayalım.

<div>
<input type="file" name="file" id="file" class="file">
<span id="value"></span>
</div>

Sonra stile gideceğiz.

    .file {
        width: 400px;
        height: 50px;
        background: #171717;
        padding: 4px;
        border: 1px dashed #333;
        position: relative;
        cursor: pointer;
    }

    .file::before {
        content: '';
        position: absolute;
        background: #171717;
        font-size: 20px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 100%;
        height: 100%;
    }

    .file::after {
        content: 'Drag & Drop';
        position: absolute;
        color: #808080;
        font-size: 20px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

Bunu yaptıktan sonra zaten iyi görünüyor. Ancak, hangi dosyayı actaully yüklediğinizi görmek istediğinizi düşünüyorum, bu yüzden biraz JavaScript yapacağız. Pfp-değer aralığını hatırlıyor musunuz? Dosya adını buradan yazdıracağız.

let file = document.getElementById('file');
file.addEventListener('change', function() {
    if(file && file.value) {
        let val = file.files[0].name;
        document.getElementById('value').innerHTML = "Selected" + val;
    }
});

Ve bu kadar.


Yakalanmamış TypeError alıyorum: Chrome altında bu kodu kullandığımda null 'addEventListener' özelliği okunamıyor - Chrome'un son sürümlerinde çalışmıyor mu?
Ateşle Ateşle Mücadele

Chrome'un son sürümünde benim için iyi çalışıyor. Doğru kimlikleri kullandığınızdan emin olun
Michael

1

@BjarkeCK tarafından harika bir çalışma. Jquery'de yöntem olarak kullanmak için çalışmalarında bazı değişiklikler yaptım:

$.fn.dropZone = function() {
  var buttonId = "clickHere";
  var mouseOverClass = "mouse-over";

  var dropZone = this[0];
  var $dropZone = $(dropZone);
  var ooleft = $dropZone.offset().left;
  var ooright = $dropZone.outerWidth() + ooleft;
  var ootop = $dropZone.offset().top;
  var oobottom = $dropZone.outerHeight() + ootop;
  var inputFile = $dropZone.find("input[type='file']");
  dropZone.addEventListener("dragleave", function() {
    this.classList.remove(mouseOverClass);
  });
  dropZone.addEventListener("dragover", function(e) {
    console.dir(e);
    e.preventDefault();
    e.stopPropagation();
    this.classList.add(mouseOverClass);
    var x = e.pageX;
    var y = e.pageY;

    if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
      inputFile.offset({
        top: y - 15,
        left: x - 100
      });
    } else {
      inputFile.offset({
        top: -400,
        left: -400
      });
    }

  }, true);
  dropZone.addEventListener("drop", function(e) {
    this.classList.remove(mouseOverClass);
  }, true);
}

$('#drop-zone').dropZone();

Çalışma keman


1
FYI: Keman bağı koptu.
jimiayler

1

Birkaç yıl sonra, dosyaları herhangi bir HTML öğesine bırakmak için bu kütüphaneyi oluşturdum.

Gibi kullanabilirsiniz

const Droppable = require('droppable');

const droppable = new Droppable({
    element: document.querySelector('#my-droppable-element')
})

droppable.onFilesDropped((files) => {
    console.log('Files were dropped:', files);
});

// Clean up when you're done!
droppable.destroy();

Form gönderilirken seçilen dosya daha sonra nasıl alınır?
Nikhil VJ

-1

Yapabileceğiniz şey, bir dosya girişini görüntülemek ve şeffaf bir bırakma alanınızla örtmek gibi bir ad kullanmaya dikkat etmektir file[1]. {Şunlara sahip olduğunuzdan emin olun:enctype="multipart/form-data" FORM etiketinizin içinin bulunduğundan .}

Daha sonra, 2. alan için dinamik olarak daha fazla dosya girişi oluşturarak bırakma alanının fazladan dosyaları işlemesini sağlayın, aynı temel adı kullandığınızdan emin olun, değer niteliğini uygun şekilde doldurun.

Son olarak (ön uç) formu gönderin.


Bu yöntemi işlemek için gereken tek şey bir dizi dosyayı işlemek için prosedürünüzü değiştirmek.


1
Dosya girdisinin multiplebu günlerde bir özelliği var. 1'den fazla dosya girişine gerek yoktur. Ancak sorun bu değil. FileNesneleri dosya girişine nasıl alabilirim ? Ben bunun bazı kod örneği gerektirdiğini düşünüyorum ...
Rudie

1
@ Yapamazsın, sorun bu.
Ricardo Tomasi

1
Ne olamaz? Çoklu? Evet yapabilirsin. Söyledimya. Çoklu sorun değil. Dosyaları bir (sürüklenen) File nesnesinden bir dosya girişine almak sorun.
Rudie

@Rudie sürüklenen dosya (lar) bir dosya girişi içine almak Chrome / FF ( filesözelliği kullanarak ) ile mümkündür, ama IE yönetemedim - herhangi bir şans oldu mu?
jlb

1
@jlb "files özelliğini kullanma" ne demek? İlgili kodla cevap verebilir misiniz? Aradığım şey hiçbir tarayıcıda çalışmıyor / mevcut değil.
Rudie
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.