На многих веб-сайтах есть форма для загрузки файла. Для некоторых сайтов, таких как OneDrive или Google Диск, загрузка файлов является основной функцией. С течением времени веб-страницы становятся все более интерактивными. Таким образом, пользователи ожидают большего количества взаимодействий, таких как перетаскивание файлов или каталогов или вставка скриншотов.

Давайте посмотрим, что предоставляют браузеры для загрузки файлов!

<form method="post" enctype="multipart/form-data">
    <input type="file" name="photo">
    <input type="submit" value="Submit">
</form>

Вы можете улучшить это с помощью двух необязательных атрибутов:

  • multiple: позволяет выбрать несколько файлов

  • accept: выберите ожидаемые mime types, например: image/*, application/pdf

Drag and drop файлов

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

const dropZone = document.body;
if (dropZone) {
    let hoverClassName = 'hover';
  
    dropZone.addEventListener("dragenter", function(e) {
        e.preventDefault();
        dropZone.classList.add(hoverClassName);
    });
  
    dropZone.addEventListener("dragover", function(e) {
        e.preventDefault();
        dropZone.classList.add(hoverClassName);
    });
  
    dropZone.addEventListener("dragleave", function(e) {
        e.preventDefault();
        dropZone.classList.remove(hoverClassName);
    });
  
    // Это самое важное событие, событие, которое дает доступ к файлам
    dropZone.addEventListener("drop", function(e) {
        e.preventDefault();
        dropZone.classList.remove(hoverClassName);

        const files = Array.from(e.dataTransfer.files);
        console.log(files);
        // TODO что-то делает с файлами...
    });
}

Вы можете легко загружать файлы в API, используя fetch API:

if (files.length > 0) {
    const data = new FormData();
    for (const file of files) {
        data.append('file', file);
    }

    fetch('/upload', {
        method: 'POST',
        body: data
    })
    .then(() => console.log("file uploaded"))
    .catch(reason => console.error(reason));
}

Drag and drop директорий

Google Chrome и Microsoft Edge теперь поддерживают перетаскивание каталогов. Это очень полезно, если вы хотите загрузить свои файлы в OneDrive или Google Диск. API не очень удобен, так как использует функции обратного вызова с рекурсивным деревом, но это не так сложно. Давайте посмотрим на какой-нибудь код:

// drag* события опущены для краткости (получите их из предыдущего раздела).
dropZone.addEventListener('drop', async function(e) {
    e.preventDefault();
    dropZone.classList.remove(hoverClassName);

    console.log(await getFileAsync(e.dataTransfer));
};

async function getFileAsync(dataTranfer) {
    const files = [];
    for (var i = 0; i < dataTranfer.items.length; i++) {
        const item = dataTranfer.items[i];
        if (item.kind === 'file') {
            if (typeof item.webkitGetAsEntry === 'function'){
                const entry = item.webkitGetAsEntry();
                const entryContent = await readEntryContentAsync(entry);
                files.push(...entryContent);
                continue;
            }

            const file = item.getAsFile();
            if (file) { files.push(file); }
        }
    }
    return files;
};

// Возвращает Promise со всеми файлами иерархии каталогов
function readEntryContentAsync(entry) {
    return new Promise((resolve, reject) => {
        let reading = 0;
        const contents = [];

        readEntry(entry);

        function readEntry(entry) {
            if (entry.isFile) {
                reading++;
                entry.file(file => {
                    reading--;
                    contents.push(file);

                    if (reading === 0) {
                        resolve(contents);
                    }
                });
            } else if (entry.isDirectory) {
                readReaderContent(entry.createReader());
            }
        };
      
        function readReaderContent(reader) {
            reading++;
            reader.readEntries(function(entries) {
                reading--;
                for (const entry of entries) {
                    readEntry(entry);
                }
                if (reading === 0) {
                    resolve(contents);
                }
            });
        };
    });
};

Теперь вы мастера загружать файлы и каталоги.

Комментарии (0)