Подтвердить что ты не робот

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

Я пытаюсь определить, перетаскивается ли папка или файл в dragover или dragenter.

Например:

В событии ondrop есть аргумент MouseEvent, который имеет поле с именем dataTransfer, где перечислены файлы (.files) или элементы (.items), в зависимости от браузера, и я могу прочитать это как в Chrome, так и в Firefox. Однако для событий dragover и dragenter эти поля (.files и .items) пусты. Проблема в том, что мне нужна эта информация при перетаскивании, а не при перетаскивании.

ПРИМЕЧАНИЕ. Для файлов и папок event.dataTransfer.types[i] === "Files" имеет значение true.

Фундаментальные исследования

Я нашел следующий ответ, который частично подходит для моего вопроса:

WebKit и, следовательно, Chrome, весьма ограничивают возможность вызова getData. Вам не разрешено делать это внутри dragstart или dragover. Я думаю, что это каноническая ошибка.

Но этот ответ с 2012 года, и я не могу найти актуальную обновленную информацию по этой теме, поэтому я ищу обновленную информацию по этому вопросу.

4b9b3361

Ответ 1

TL;DR you can't :(

If you're wondering why this question still hasn't got an accepted answer, you can read this meta question created by the OP, and my answer.

Файл drag/drop в HTML5

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

Перетаскивание

При перетаскивании файла вы можете использовать несколько слушателей, например:

  • dragenter
  • dragover
  • dragend
  • dragleave

Учитывая, что это события drag, свойство files для event.dataTransfer будет иметь length == 0 или быть пустым (null).

Вы не можете прочитать информацию о файлах в событии перетаскивания и не можете проверить, являются ли они папками. Это не ошибка, это мера безопасности.

Представьте, что вы можете читать файлы в событии перетаскивания: вы сможете читать все, даже если пользователь не хочет загружать файлы на ваш сайт. Это не имеет смысла, серьезно. Представьте, что вы перетаскиваете файл со своего рабочего стола в другую папку и случайно перетаскиваете его через веб-страницу: теперь веб-страница читает ваш файл и сохраняет вашу личную информацию на своем сервере... , что было бы огромным недостатком безопасности.

Однако вы все равно сможете определить, перетаскивает ли пользователь файлы (и под файлами, я имею в виду и папки, потому что папки являются файлами), или нет, перебирая массив event.dataTransfer.types. Вы можете создать функцию, которая проверяет, содержат ли событие перетаскивания файлы, а затем вызывать ее в обработчике событий.

Пример:

function containsFiles(event) {
    if (event.dataTransfer.types) {
        for (var i=0; i<event.dataTransfer.types.length; i++) {
            if (event.dataTransfer.types[i] == "Files") {
                return true;
            }
        }
    }

    return false;
}

function handleDragEnter(e) {
    e.preventDefault();
    if (containsFiles(e)) {
        // The drag event contains files
        // Do something
    } else {
        // The drag event does not contain files
        // Do something else
    }
}

капают

Когда вы помещаете файл в <div> (или любой другой элемент, который вы используете в качестве dropzone), вы будете использовать прослушиватель для события drop для чтения некоторых свойств файла, таких как имя, размер, тип и дата последнего изменения..

Чтобы определить, является ли файл папкой, вы должны:

  1. Проверьте, есть ли в файле type == "", потому что у папок нет типа.
  2. Проверьте, кратен ли размер файла 4096: size%4096 == 0, поскольку размер папок всегда кратен 4096 байтам (что составляет 4 КБ).

Пример:

function handleDrop(e) {
    e.stopPropagation();
    e.preventDefault();

    var files = e.dataTransfer.files;

    for (var i = 0, f; f = files[i]; i++) { // iterate in the files dropped
        if (!f.type && f.size%4096 == 0) {
            // The file is a folder
            // Do something
        } else {
            // The file is not a folder
            // Do something else
        }
    }
}

ИЗВЕСТНЫЙ ПРОБЛЕМА: Поскольку эти папки на самом деле являются файлами, это единственный способ отличить их от файлов другого типа. Хотя этот метод не дает вам абсолютной уверенности в том, что файл является папкой: это может быть файл без расширения и размером 0 или ровно N x 4096B.


Рабочие примеры

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

Ответ 2

Это работа над событием Dropping -on drop (обратите внимание, что это не работает с событием dragover):

isDraggedItemIsFile = function(e) {
// handle FF
if (e.originalEvent.dataTransfer.files.length == 0) {
    return false;
}
// handle Chrome
if (e.originalEvent.dataTransfer.items) {
    if (typeof (e.originalEvent.dataTransfer.items[0].webkitGetAsEntry) == "function") {
        return e.originalEvent.dataTransfer.items[0].webkitGetAsEntry().isFile;
    } else if (typeof (e.originalEvent.dataTransfer.items[0].getAsEntry) == "function") {
        return e.originalEvent.dataTransfer.items[0].getAsEntry().isFile;
    }
}
return true;
};

$forms.on('drop', function(e) {
        if (isDraggedItemIsFile(e)) {
            // do something if file
        } else{
           // is directory
        }
    });

Протестировано на FF V49, Chrome V55, Edge V25

Ответ 3

Вы можете отделить файлы от папок с помощью FileReader или с помощью webkitGetAsEntry()

WebkitGetAsEntry() не поддерживается ie11, так что имейте это в виду!

Код будет выглядеть так:

 onDrop(event) {
    let files = event.dataTransfer ? event.dataTransfer.files : 'null';

    for(let i = 0, file; file = files[i]; i++) {
       var reader = new FileReader();

       reader.onload = function (e) {
           console.log('it is a file!');
       };
       reader.onerror = function (e) {
          console.log('it is a folder!');
       };

       reader.readAsText(file);
    }

}

Ответ 4

Я смог получить весь Mimetype этой вещи, перетаскиваемой по моей странице. Mimetype кажется пустым для папок, так что, возможно, вы сможете отличить его таким образом.

Частичный код (извлечен из React):

function handleDragOver(ev: DragEvent) {
    ev.preventDefault();
    ev.dataTransfer!.dropEffect = 'copy';
    console.log(Array.from(ev.dataTransfer.items).map(i => [i.kind,i.type].join('|')).join(', '));
}

document.addEventListener('dragover',handleDragOver);

Вывод выглядит так:

file|image/x-icon, file|image/jpeg, file|application/vnd.ms-excel

Когда я перетаскиваю 3 файла на мою страницу.

Не уверен, что это работает только на localhost, я еще нигде не загрузил, но это полностью работает.

MDN документы на DataTransferItem