JavaScript/HTML5/jQuery Drag-and-Drop Upload - "Uncaught TypeError: Невозможно прочитать свойства" файлы "с неопределенным"

До этого я сообщу вам, что у меня ограниченный опыт работы с JavaScript.


В настоящее время у меня есть код JavaScript:

$('#xhr-filebox').bind({
    "dragover": HandleDragEvent,
    "dragleave": HandleDragEvent,
    "drop": HandleDropEvent
});

function HandleDropEvent(e){
    var files = e.target.files || e.dataTransfer.files;
    UploadFile(files[0]);
}

(некоторый код опущен, но я добавлю больше, если вы попросите)

... и HTML:

<div class="filebox" id="xhr-filebox">
    <p id="xhr-action">...or click me to pick one.</p>
</div>

Однако когда я перетаскиваю в него файл, консоль Chrome JS сообщает следующее:

Uncaught TypeError: Невозможно прочитать свойство 'files' из неопределенного

Однако он может получить объект FileList при чтении из файла ввода.

Любопытно, что когда я регистрирую аргумент события ( console.log(e)), он регистрирует его как f.event, тогда как в моем похожем скрипте он регистрирует его как MouseEvent (снимок экрана: )

В отличие от функции bind() в jQuery, здесь используется функция addEventListener() объекта DOM, возвращаемого getElementById(), т.е. это чистый JavaScript. Я попробовал этот метод, но ничего нового не происходит.

2 ответа

Решение

Если files не существует на e.targetвы ищете files на e.dataTransfer - но если нет dataTransfer собственность на e (а на скриншоте его нет) вы попытаетесь разыменовать undefined, в результате чего эта ошибка.

Я бы изменил код на:

function HandleDropEvent(e){
    var files = e.target.files || (e.dataTransfer && e.dataTransfer.files);
    if (files) {
        UploadFile(files[0]);
    }
    else {
        // Perhaps some kind of message here
    }
}

Таким образом, если e.target.files не существует и e.dataTransfer также не существует, вы получите files являющийся undefined, а не ошибка.


Объект события, который дает вам jQuery, создается и нормализуется с помощью jQuery. Так как мы знаем e.dataTransfer не существует для этого объекта события (из вашего скриншота), я предполагаю, что это не одно из свойств, копируемых jQuery из исходного объекта события. Это нормально, потому что jQuery дает нам доступ к исходному событию через e.originalEvent, Итак, я бы попробовал:

function HandleDropEvent(e){
    var dt = e.dataTransfer || (e.originalEvent && e.originalEvent.dataTransfer);
    var files = e.target.files || (dt && dt.files);
    if (files) {
        UploadFile(files[0]);
    }
    else {
        // Perhaps some kind of message here
    }
}

Что хватает files от e.target если это где он есть, или из dataTransfer объект, где бы мы его не нашли (на eили на e.originalEvent).

Я использовал следующий код в течение последних нескольких лет:

var files = e.target.files || 
(e.dataTransfer ? e.dataTransfer.files : e.originalEvent.dataTransfer.files);

Однако недавно я столкнулся с проблемой использования Chrome, где был файл e.target.files, но с длиной 0, из-за которого файлы были пустыми, даже если в dataTransfer действительно были отброшенные файлы.

Итак, мне пришлось использовать немного другую проверку:

var files = e.target.files;
if (!files || files.length === 0)
    files = (e.dataTransfer ? e.dataTransfer.files : e.originalEvent.dataTransfer.files);

Надеюсь, это может помочь кому-то еще.

Другие вопросы по тегам