Tarayıcının sürükleyip bırakılan bir dosyayı yüklemesini önleme


194

Sayfama bir html5 sürükle ve bırak yükleyicisi ekliyorum.

Bir dosya yükleme alanına bırakıldığında her şey harika çalışır.

Ancak, dosyayı yanlışlıkla yükleme alanının dışına bırakırsam, tarayıcı yerel dosyayı yeni bir sayfa gibi yükler.

Bu davranışı nasıl önleyebilirim?

Teşekkürler!


2
Html5 sürükle / bırak yüklemesini işlemek için hangi kodu kullandığınızı merak ediyorsunuz. Teşekkürler.
robertwbradford

Karşılaştığınız soruna, drop / dragenter / etc dosyasında e.dataTransfer () eksik veya bir preventDefault () eksik olmasından kaynaklanır. Etkinlikler. Ama bir kod örneği olmadan söyleyemem.
HoldOffHunger

Yanıtlar:


314

preventDefault()Tüm dragover ve drop olaylarını çağıran pencereye bir olay dinleyicisi ekleyebilirsiniz .
Misal:

window.addEventListener("dragover",function(e){
  e = e || event;
  e.preventDefault();
},false);
window.addEventListener("drop",function(e){
  e = e || event;
  e.preventDefault();
},false);

45
dragover kaçırdığım parçadır.
cgatian

11
Hem teyit dragoverve dropişleyicileri düştü dosyayı yüklenmesini engellemek tarayıcı ihtiyaç vardır. (Chrome en son 2015/08/03). Çözüm en son FF üzerinde de çalışıyor.
Offirmo

4
Bu mükemmel çalışıyor ve resumable.js gibi sürükle ve bırak dosya yükleme komut dosyalarında olduğu gibi bırakma olaylarını kabul etmek üzere yapılandırılmış sayfa öğeleriyle birlikte kullanılabileceğini onaylayabilirim. Kullanıcının yüklemek istediği dosyayı gerçek dosya yükleme bırakma alanının dışına yanlışlıkla düşürmesi ve ardından aynı dosyanın neden doğrudan tarayıcı penceresinde işlendiğini görmesi durumunda varsayılan tarayıcı davranışını önlemek yararlıdır ( resim veya video gibi uyumlu bir dosya türünün kaldırıldığı varsayılarak), dosya yüklemelerini görme beklenen davranışı yerine.
bluebinary

15
Not: Bu ayrıca dosyaların a <input type="file" />. e.targetBir dosya girişi olup olmadığını kontrol etmek ve bu tür olayların geçmesine izin vermek gerekir.
Sebastian Nowak

6
ne ? neden pencere dragover dosyayı yüklemek gerekir? bu hiç mantıklı değil ...
L.Trabacchin

38

Etrafta çok uğraştıktan sonra, bunun en istikrarlı çözüm olduğunu gördüm:

var dropzoneId = "dropzone";

window.addEventListener("dragenter", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
}, false);

window.addEventListener("dragover", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
});

window.addEventListener("drop", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
});
<div id="dropzone">...</div>

Her iki ayarlama effectAllowve dropEffectpencere koşulsuz benim damla bölge özelliklerini yeni set olsun ya da olmasın bakılmaksızın, artık herhangi DND kabul etmeme neden olur.


e.dataTransfer () burada "kabul edilen cevap" ın sözünü edemediği bu işi yapan kritik parçadır.
HoldOffHunger

9

JQuery için doğru cevap:

$(document).on({
    dragover: function() {
        return false;
    },
    drop: function() {
        return false;
    }
});

İşte ve return falsegibi davranacak .event.preventDefault()event.stopPropagation()


9

Yalnızca bazı öğelerde sürükle ve bırak işlemine izin vermek için aşağıdakileri yapabilirsiniz:

window.addEventListener("dragover",function(e){
  e = e || event;
  console.log(e);
  if (e.target.tagName != "INPUT") { // check which element is our target
    e.preventDefault();
  }
},false);
window.addEventListener("drop",function(e){
  e = e || event;
  console.log(e);
  if (e.target.tagName != "INPUT") {  // check which element is our target
    e.preventDefault();
  }  
},false);

Benim için mükemmel çalışıyor, ancak ayrıca type = file için kontrol ekleyeceğim, aksi takdirde hala metin girişlerine sürükleyebilirsiniz
Andreas Zwerger

2

bunu dene:

document.body.addEventListener('drop', function(e) {
    e.preventDefault();
}, false);

2

Varsayılan olarak tüm sürükle ve bırak işlemlerini önlemek istediğiniz şey olmayabilir. En azından bazı tarayıcılarda sürükleme kaynağının harici bir dosya olup olmadığını kontrol etmek mümkündür. Sürükleme kaynağının bu StackOverflow yanıtında harici bir dosya olup olmadığını kontrol etmek için bir işlev ekledim .

Digital Plane'nun cevabını değiştirerek, böyle bir şey yapabilirsiniz:

function isDragSourceExternalFile() {
     // Defined here: 
     // https://stackoverflow.com/a/32044172/395461
}

window.addEventListener("dragover",function(e){
    e = e || event;
    var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
    if (IsFile) e.preventDefault();
},false);
window.addEventListener("drop",function(e){
    e = e || event;
    var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
    if (IsFile) e.preventDefault();
},false);

1
Ne anlamı var e || event;? Nerede eventtanımlı? Boşver. IE'de küresel bir nesne gibi görünüyor? Bu teklifi buldum, "In Microsoft Visual Basic Scripting Edition (VBScript), you must access the event object through the window object." burada
1.21 gigawatts

2

Not: OP bir Açısal çözüm istemese de buraya geldim. Bu, eğer Angular kullanırsanız, uygun bir çözüm olarak bulduğum şeyi paylaşmaktır.

Benim durumumda, bu sorun ilk olarak bir sayfaya dosya bırakma işlevselliği eklediğinizde ortaya çıkar. Bu nedenle, bunu ekleyen bileşenin, bırakma alanının dışına düşmeyi önlemekten de sorumlu olması gerektiğidir.

Benim çözümümde bırakma bölgesi bir sınıf ile bir girdi, ancak herhangi bir kesin seçici çalışıyor.

import { Component, HostListener } from '@angular/core';
//...

@Component({
  template: `
    <form>
      <!-- ... -->
      <input type="file" class="dropzone" />
    </form>
  `
})
export class MyComponentWithDropTarget {

  //...

  @HostListener('document:dragover', ['$event'])
  @HostListener('drop', ['$event'])
  onDragDropFileVerifyZone(event) {
    if (event.target.matches('input.dropzone')) {
      // In drop zone. I don't want listeners later in event-chain to meddle in here
      event.stopPropagation();
    } else {
      // Outside of drop zone! Prevent default action, and do not show copy/move icon
      event.preventDefault();
      event.dataTransfer.effectAllowed = 'none';
      event.dataTransfer.dropEffect = 'none';
    }
  }
}

Bileşenler oluşturulduğunda / yok edildiğinde dinleyiciler otomatik olarak eklenir / kaldırılır ve aynı sayfada aynı stratejiyi kullanan diğer bileşenler, stopPropagation () nedeniyle birbirini etkilemez.


Bu bir cazibe gibi çalışır !! Tarayıcı bile çok büyük bir yasak simgesi ekleyerek fare imlecini değiştirmek !!
pti_jul

1

Birkaç cevapta özetlenen "hedefi kontrol et" yöntemi üzerine inşa etmek için daha genel / fonksiyonel bir yöntem:

function preventDefaultExcept(predicates) {
  return function (e) {
    var passEvery = predicates.every(function (predicate) { return predicate(e); })
    if (!passEvery) {
      e.preventDefault();
    }
  };
}

Şöyle denir:

function isDropzone(e) { return e.target.id === 'dropzone'; }
function isntParagraph(e) { return e.target.tagName !== 'p'; }

window.addEventListener(
  'dragover',
  preventDefaultExcept([isDropzone, isntParagraph])
);
window.addEventListener(
  'drop',
  preventDefaultExcept([isDropzone])
);

Ayrıca, burada bazı ES6 ekleyebilirsiniz: function preventDefaultExcept(...predicates){}. Ve sonra bunu kullanınpreventDefaultExcept(isDropzone, isntParagraph)
hlfrmn

0

Sayfanın genişliğini ve yüksekliğini dolduran bir HTML object( embed) var. @ Digital-plane tarafından verilen cevap normal web sayfalarında çalışır ancak kullanıcı katıştırılmış bir nesneye düşerse işe yaramaz. Bu yüzden farklı bir çözüme ihtiyacım vardı.

Olay yakalama aşamasını kullanmaya başlarsak , katıştırılmış nesne onları almadan önce olayları alabiliriz ( trueolay dinleyicisi çağrısının sonundaki değere dikkat edin ):

// document.body or window
document.body.addEventListener("dragover", function(e){
  e = e || event;
  e.preventDefault();
  console.log("over true");
}, true);

document.body.addEventListener("drop", function(e){
  e = e || event;
  e.preventDefault();
  console.log("drop true");
}, true);

Aşağıdaki kodu kullanarak (@ digital-plane'nin cevabına dayanarak) sayfa sürükleme hedefi haline gelir, nesne yerleştirmelerinin olayları yakalamasını önler ve ardından görüntülerimizi yükler:

document.body.addEventListener("dragover", function(e){
  e = e || event;
  e.preventDefault();
  console.log("over true");
}, true);

document.body.addEventListener("drop",function(e){
  e = e || event;
  e.preventDefault();
  console.log("Drop true");

  // begin loading image data to pass to our embed
  var droppedFiles = e.dataTransfer.files;
  var fileReaders = {};
  var files = {};
  var reader;

  for (var i = 0; i < droppedFiles.length; i++) {
    files[i] = droppedFiles[i]; // bc file is ref is overwritten
    console.log("File: " + files[i].name + " " + files[i].size);
    reader = new FileReader();
    reader.file = files[i]; // bc loadend event has no file ref

    reader.addEventListener("loadend", function (ev, loadedFile) {
      var fileObject = {};
      var currentReader = ev.target;

      loadedFile = currentReader.file;
      console.log("File loaded:" + loadedFile.name);
      fileObject.dataURI = currentReader.result;
      fileObject.name = loadedFile.name;
      fileObject.type = loadedFile.type;
      // call function on embed and pass file object
    });

    reader.readAsDataURL(files[i]);
  }

}, true);

Mac'te Firefox'ta test edildi.


0

Birden fazla yükleme alanı için bir sınıf seçici kullanıyorum, bu yüzden çözümüm bu daha az saf formu aldı

Axel Amthor'un cevabına dayanarak, jQuery'ye bağımlı olarak ($ ​​olarak takma)

_stopBrowserFromOpeningDragAndDropPDFFiles = function () {

        _preventDND = function(e) {
            if (!$(e.target).is($(_uploadBoxSelector))) {
                e.preventDefault();
                e.dataTransfer.effectAllowed = 'none';
                e.dataTransfer.dropEffect = 'none';
            }
        };

        window.addEventListener('dragenter', function (e) {
            _preventDND(e);
        }, false);

        window.addEventListener('dragover', function (e) {
            _preventDND(e);
        });

        window.addEventListener('drop', function (e) {
            _preventDND(e);
        });
    },
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.