it-roy-ru.com

Запретить браузеру загрузку файла перетаскивания

Я добавляю html5 drag and drop uploader на мою страницу.

Когда файл попадает в область загрузки, все отлично работает.

Однако, если я случайно уронил файл за пределы области загрузки, браузер загрузит локальный файл, как будто это новая страница.

Как я могу предотвратить это поведение?

Спасибо!

151
Travis

Вы можете добавить прослушиватель событий в окно, которое вызывает preventDefault() для всех событий перетаскивания и удаления.
Пример:

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

После долгих раздумий я обнаружил, что это самое стабильное решение:

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>

Безусловное задание в окне параметров effectAllow и dropEffect приводит к тому, что моя зона перетаскивания больше не принимает d-n-d независимо от того, заданы ли новые свойства или нет.

26
Axel Amthor

Чтобы разрешить перетаскивание только для некоторых элементов, вы можете сделать что-то вроде:

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);
8
enthus1ast

Для jQuery правильный ответ будет:

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

Здесь return false будет вести себя как event.preventDefault() и event.stopPropagation().

7
VisioN

попробуй это:

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

Предотвращение всех операций перетаскивания по умолчанию может оказаться не тем, что вам нужно. Можно проверить, является ли источник перетаскивания внешним файлом, по крайней мере, в некоторых браузерах. Я включил функцию, чтобы проверить, является ли источник перетаскивания внешним файлом в этом ответе StackOverflow

Изменив ответ Digital Plane, вы можете сделать что-то вроде этого: 

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);
2
Shannon

Чтобы построить метод проверки цели, описанный в нескольких других ответах, вот более общий/функциональный метод:

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

Называется как:

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])
);
1
scott_trinh

Я использую селектор классов для нескольких областей загрузки, поэтому мое решение приняло эту менее чистую форму

Основано на ответе Акселя Амтора с зависимостью от jQuery (с псевдонимом $)

_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);
        });
    },
0
hngr18

У меня есть HTML object (embed), который заполняет ширину и высоту страницы. Ответ @ digital-plane работает на обычных веб-страницах, но не в том случае, если пользователь падает на внедренный объект. Поэтому мне нужно было другое решение. 

Если мы переключимся на использование фазы захвата событий мы сможем получить события до того, как встроенный объект их получит (обратите внимание на значение true в конце вызова слушателя событий): 

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

Используя следующий код (основываясь на ответе @ digital-plane), страница становится целью перетаскивания, она предотвращает встраивание объектов в события и затем загружает наши изображения: 

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

Протестировано на Firefox на Mac. 

0
1.21 gigawatts