- Загрузка файлов
- Стилизация Input File
- 1. Стилизация input type file
- 1.1 Кнопка «Прикрепить файл» — HTML, CSS
- 1.2 Кнопка «Прикрепить файл» — JavaScript
- 2. Drag-and-drop загрузка файлов
- 2.1 Drag-and-drop — HTML, CSS
- 2.2 Drag-and-drop загрузка файлов — JavaScript
- 3. Совместное использование кнопки «Прикрепить файл» и Drag-and-drop
- 4. Отправка множества input file multiple
- Статьи из данной категории:
Загрузка файлов
Для того чтобы можно было загружать на сервер один или несколько файлов, в форме применяется специальное поле. В браузерах Firefox, IE и Opera такой элемент отображается как текстовое поле, рядом с которым располагается кнопка с надписью «Обзор. » (рис. 1). В Safari и Chrome доступна только кнопка «Выберите файл» (рис. 2).
Рис. 1. Вид поля для загрузки файла в Firefox
Рис. 2. Загрузка файлов в Chrome
При нажатии на кнопку открывается окно для выбора файла, где можно указать, какой файл пользователь желает использовать.
Синтаксис поля для отправки файла следующий.
Атрибуты перечислены в табл. 1.
Атрибут | Описание |
---|---|
accept | Устанавливает фильтр на типы файлов, которые вы можете отправить через поле загрузки файлов. |
size | Ширина текстового поля, которое определяется числом символов моноширинного шрифта. |
multiple | Позволяет выбирать и загружать сразу несколько файлов. |
name | Имя поля, используется для его идентификации обработчиком формы. |
Прежде, чем использовать данное поле, в форме необходимо сделать следующее:
- задать метод отправки данных POST ( method=»post» );
- установить у атрибута enctype значение multipart/form-data .
Форма для загрузки файла продемонстрирована в примере 1.
Пример 1. Создание поля для отправки файла
Хотя можно установить ширину поля через атрибут size , в действительности ширина никак не влияет на результат работы формы. В браузерах Safari и Chrome этот атрибут вообще никакого воздействия не оказывает.
Атрибут multiple более важен, он позволяет не ограничиваться одним файлом для выбора, а указать их сразу несколько для одновременной загрузки.
Если атрибут accept не указывать, тогда добавляются и загружаются файлы любого типа. Наличие accept позволяет ограничить выбор файла, что особенно важно, когда требуется загрузить только изображение или видео. В качестве значения выступает MIME-тип, несколько значений разделяются между собой запятой. Также можно использовать следующие ключевые слова:
- audio/* — выбор музыкальных файлов любого типа;
- image/* — графические файлы;
- video/* — видеофайлы.
В табл. 2 показаны некоторые допустимые значения атрибута accept .
Значение | Описание |
---|---|
image/jpeg | Только файлы в формате JPEG. |
image/jpeg,image/png | Только файлы в формате JPEG и PNG. |
image/* | Любые графические файлы. |
image/*,video/* | Любые графические и видеофайлы. |
Использование дополнительных атрибутов показано в примере 2.
Пример 2. Загрузка фотографий
Не все браузеры поддерживают новые атрибуты. IE полностью игнорирует multiple и accept , Safari не поддерживает accept , а Firefox не работает с MIME-типом, только с ключевыми словами. Поэтому в примере выше специально для Firefox установлено значение image/*,image/jpeg . Также учтите странную ошибку в Опере, она не допускает пробелы после запятой внутри accept .
Результат примера показан на рис. 3. Обратите внимание, что из-за наличия multiple несколько изменился вид поля.
Рис. 3. Загрузка файлов в Opera
Стилизация Input File
Сегодня будем стилизовать input type file. Т.к. стилизация тесно связана с обработкой input file на фронтенде, мы так же рассмотрим, как обработать выбранный файл и отправить на сервер. Скрипт будет работать для множества форм с возможностью не только загрузить файл при клике на кнопку, но так же перетаскиванием файла (drag-and-drop) в область загрузки. Если вам не нужен тот или иной функционал, вы легко сможете удалить часть кода.
1. Стилизация input type file
1.1 Кнопка «Прикрепить файл» — HTML, CSS
Сначала нам необходимо создать html-разметку.
- multiple — данный атрибут необходим, если вы хотите разрешить отправку более одного файла;
- accept — в данный атрибут запишите типы файлов (MIME-типы), которые разрешены для выбора.
Скроем input и стилизуем кнопку для загрузки файла.
.upload-file__input < opacity: 0; position: absolute; z-index: -1; overflow: hidden; width: 0.4px; height: 0.4px; >.upload-file__label < display: flex; justify-content: center; align-items: center; max-width: 240px; border: 2px dashed #150B22; padding: 9px 49px; border-radius: 6px; cursor: pointer; >.upload-file__icon < width: 30px; height: auto; margin-right: 11px; >.upload-file__label .upload-file__text, .upload-file__label .upload-file__icon path < transition: .25s ease; >.upload-file__label:hover .upload-file__text < color: #58862D; >.upload-file__label:hover .upload-file__icon path < fill: #58862D; >.upload-file__label:hover
1.2 Кнопка «Прикрепить файл» — JavaScript
document.addEventListener("DOMContentLoaded", () => < const forms = document.querySelectorAll("form"); const inputFile = document.querySelectorAll(".upload-file__input"); /////////// Кнопка «Прикрепить файл» /////////// inputFile.forEach(function(el) < let textSelector = document.querySelector(".upload-file__text"); let fileList; // Событие выбора файла(ов) el.addEventListener("change", function (e) < // создаём массив файлов fileList = []; for (let i = 0; i < el.files.length; i++) < fileList.push(el.files[i]); >// вызов функции для каждого файла fileList.forEach(file => < uploadFile(file); >); >); // Проверяем размер файлов и выводим название const uploadFile = (file) => < // файла 5 * 1024 * 1024) < alert("Файл должен быть не более 5 МБ."); return; >// Показ загружаемых файлов if (file && file.length > 1) < if ( file.length файла`; > if ( file.length > 4 ) < textSelector.textContent = `Выбрано $файлов`; > > else < textSelector.textContent = file.name; >> >); // Отправка формы на сервер const postData = async (url, fData) => < // имеет асинхронные операции // начало отправки // здесь можно оповестить пользователя о начале отправки // ждём ответ, только тогда наш код пойдёт дальше let fetchResponse = await fetch(url, < method: "POST", body: fData >); // ждём окончания операции return await fetchResponse.text(); >; if (forms) < forms.forEach(el => < el.addEventListener("submit", function (e) < e.preventDefault(); // создание объекта FormData let fData = new FormData(this); // Добавление файлов input type file let file = el.querySelector(".upload-file__input"); for (let i = 0; i < (file.files.length); i++) < fData.append("files[]", file.files[i]); // добавляем файлы в объект FormData() >// Отправка на сервер postData("./mail.php", fData) .then(fetchResponse => < console.log("Данные успешно отправлены!"); console.log(fetchResponse); >) .catch(function (error) < console.log("Ошибка!"); console.log(error); >); >); >); >; >);
2. Drag-and-drop загрузка файлов
Структура останется прежней, т.к. наша первоначальная разметка вполне подойдёт для создания drag-and-drop области.
2.1 Drag-and-drop — HTML, CSS
Улучшим юсабилити путём добавления стилей для drag-and-drop .
/* drag and drop - "hover" */ .upload-file__label.hover .upload-file__text < color: #ffb300; >.upload-file__label.hover .upload-file__icon path < fill: #ffb300; >.upload-file__label.hover < border: 2px dashed #ffb300; >/* drag and drop - ошибка */ .upload-file__label.error .upload-file__text < color: #d32f2f; >.upload-file__label.error .upload-file__icon path < fill: #d32f2f; >.upload-file__label.error < border: 2px dashed #d32f2f; >/* drag and drop - файл(ы) успешно перетянут(ы) */ .upload-file__label.drop .upload-file__text < color: #388e3c; >.upload-file__label.drop .upload-file__icon path < fill: #388e3c; >.upload-file__label.drop
2.2 Drag-and-drop загрузка файлов — JavaScript
Теперь напишем JavaScript для обработки событий перетаскивания файлов на веб-страницу. А уже в следующем пункте рассмотрим, как использовать кнопку добавления файла и область Drag-and-drop одновременно.
document.addEventListener("DOMContentLoaded", () => < const forms = document.querySelectorAll("form"); /////////// Загрузка файлов при помощи «Drag-and-drop» /////////// const dropZone = document.querySelector(".upload-file__label"); const dropZoneText = document.querySelector(".upload-file__text"); const maxFileSize = 5000000; // максимальный размер файла - 5 мб. let uploadDragFile = ""; // Проверка поддержки «Drag-and-drop» if (typeof (window.FileReader) == "undefined") < dropZone.textContent = "Drag&Drop Не поддерживается браузером!"; dropZone.classList.add("error"); >// Событие - перетаскивания файла dropZone.ondragover = function () < this.classList.add("hover"); return false; >; dropZone.ondragleave = function () < this.classList.remove("hover"); return false; >; let uploadDragFiles = ""; dropZone.ondrop = function (e) < // Событие - файл перетащили e.preventDefault(); this.classList.remove("hover"); this.classList.add("drop"); uploadDragFiles = e.dataTransfer.files; // Проверка размера файла if (uploadDragFiles[0].size >maxFileSize) < dropZoneText.textContent = "Размер превышает допустимое значение!"; this.addClass("error"); return false; >// Показ загружаемых файлов if (uploadDragFiles.length > 1) < if (uploadDragFiles.length файла`; > else < dropZoneText.textContent = `Выбрано $файлов`; > > else < dropZoneText.textContent = e.dataTransfer.files[0].name; >> // Отправка формы на сервер const postData = async (url, fData) => < // имеет асинхронные операции // начало отправки // здесь можно оповестить пользователя о начале отправки // ждём ответ, только тогда наш код пойдёт дальше let fetchResponse = await fetch(url, < method: "POST", body: fData >); // ждём окончания операции return await fetchResponse.text(); >; if (forms) < forms.forEach(el => < el.addEventListener("submit", function (e) < e.preventDefault(); // создание объекта FormData let fData = new FormData(this); // Добавление файлов input type file let file = el.querySelector(".upload-file__input"); for (let i = 0; i < (file.files.length); i++) < fData.append("files[]", file.files[i]); // добавляем файлы в объект FormData() >// Отправка на сервер postData("./mail.php", fData) .then(fetchResponse => < console.log("Данные успешно отправлены!"); console.log(fetchResponse); >) .catch(function (error) < console.log("Ошибка!"); console.log(error); >); >); >); >; >);
3. Совместное использование кнопки «Прикрепить файл» и Drag-and-drop
Теперь рассмотрим случай, когда нам необходимо чтобы пользователь имел возможность прикрепить файл любым из этих способов.
HTML-структура и CSS останутся без изменений. Объеденим JavaScript код.
document.addEventListener("DOMContentLoaded", () => < const forms = document.querySelectorAll("form"); for (let i = 1; i document.querySelectorAll(".upload-file__wrapper").forEach(function (current_item, index) < const inputFile = current_item.querySelector(".upload-file__input"); // создаём массив файлов let fileList = []; /////////// Кнопка «Прикрепить файл» /////////// let textSelector = current_item.querySelector(".upload-file__text"); // Событие выбора файла(ов) inputFile.addEventListener("change", function () < fileList.push(. inputFile.files); // console.log(inputFile.files); // вызов функции для каждого файла fileList.forEach(file =>< uploadFile(file); >); >); // Проверяем размер файлов и выводим название const uploadFile = (file) => < // размер файла 5 * 1024 * 1024) < alert("Файл должен быть не более 5 МБ."); return; >// Показ загружаемых файлов if (file && fileList.length > 1) < if (fileList.length файла`; > else < textSelector.textContent = `Выбрано $файлов`; > > else < textSelector.textContent = file.name; >fileList = []; > /////////// Загрузка файлов при помощи «Drag-and-drop» /////////// // const dropZones = document.querySelectorAll(".upload-file__label"); const dropZone = current_item.querySelector(".upload-file__label"); const dropZoneText = current_item.querySelector(".upload-file__text"); const maxFileSize = 5000000; // максимальный размер файла - 5 мб. // Проверка поддержки «Drag-and-drop» if (typeof (window.FileReader) == "undefined") < dropZone.textContent = "Drag&Drop Не поддерживается браузером!"; dropZone.classList.add("error"); >// Событие - перетаскивания файла dropZone.ondragover = function () < this.classList.add("hover"); return false; >; // Событие - отмена перетаскивания файла dropZone.ondragleave = function () < this.classList.remove("hover"); return false; >; // Событие - файл перетащили dropZone.addEventListener("drop", function (e) < e.preventDefault(); this.classList.remove("hover"); this.classList.add("drop"); uploadDragFiles = e.dataTransfer.files[0]; // один файл // Проверка размера файла if (uploadDragFiles.size >maxFileSize) < dropZoneText.textContent = "Размер превышает допустимое значение!"; this.addClass("error"); return false; >// Показ загружаемых файлов if (uploadDragFiles.length > 1) < if (uploadDragFiles.length файла`; > else < dropZoneText.textContent = `Выбрано $файлов`; > > else < dropZoneText.textContent = e.dataTransfer.files[0].name; >// добавляем файл в объект "uploadDragFiles_i" window["uploadDragFiles_"+index] = uploadDragFiles; >); >); // Отправка формы на сервер const postData = async (url, fData) => < // имеет асинхронные операции // начало отправки // здесь можно сообщить пользователю о начале отправки // ждём ответ, только тогда наш код пойдёт дальше let fetchResponse = await fetch(url, < method: "POST", body: fData >); // ждём окончания операции return await fetchResponse.text(); >; if (forms) < forms.forEach(el => < el.addEventListener("submit", function (e) < e.preventDefault(); // создание объекта FormData let fData = new FormData(this); // Добавление файлов input type file el.querySelectorAll(".upload-file__input").forEach((one_file, index) => < for (let i = 0; i < (one_file.files.length); i++) < fData.append("files[]", one_file.files[i]); // добавляем файлы, добавленные кнопкой >fData.append("files[]", window["uploadDragFiles_"+index]); // добавляем drug-&-drop файлы >); // Отправка на сервер postData("./mail-files.php", fData) .then(fetchResponse => < swal(< title: "Спасибо!", text: "Данные отправлены.", icon: "success", button: "Ok" >); // console.table("Данные успешно отправлены!", fetchResponse); el.reset(); // Очистка полей формы document.querySelectorAll(".upload-file__text").forEach(this_text => < this_text.textContent = "Выберите файл или перетащите в поле"; >); >) .catch(function (error) < swal(< title: error, icon: "error", button: "Ok" >); // console.table("Ошибка!", error); >); >); >); >; >);
4. Отправка множества input file multiple
Ранее мы успешно отправили все даннные формы (текстовые поля и файлы) на сервер.
Рассмотрим пример отправки multiple формы с множеством input file на почту.
$file) < $path = __DIR__ . "/upload-files/" . $file; // путь загрузки файла if (copy($_FILES["files"]["tmp_name"][$key], $path)) < $file_attach[] = $path; >> > $c = true; foreach ($_POST as $key => $value) < if (is_array($value)) < $value = implode(", ", $value); >if ( $value != "" && $key != "project_name" && $key != "admin_email" && $key != "form_subject" && $key != "file_attach" ) < $message .= (($c = !$c) ? "" : " ") . " $key $value "; > > $message = ' $project_name. $form_subject ' . $message . '
'; // Отправляем сообщение if (empty($file_attach)) < $headers = "MIME-Version: 1.0" . PHP_EOL . "Content-Type: text/html; charset=utf-8" . PHP_EOL . "From: " . $project_name . " " . PHP_EOL . "Reply-To: " . $admin_email . "" . PHP_EOL; mail($admin_email, $form_subject, $message, $headers); # отправка текста > else < send_mail($admin_email, $form_subject, $message, $file_attach); # отправка файлов >// Функция для отправки сообщения с вложением function send_mail($to, $form_subject, $html, $paths) < $boundary = "--" . md5(uniqid(time())); // генерируем разделитель $headers = "MIME-Version: 1.0\n"; $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\n"; $multipart = "--$boundary\n"; $multipart .= "Content-Type: text/html; charset='utf-8'\n"; $multipart .= "Content-Transfer-Encoding: Quot-Printed\n\n"; $multipart .= "$html\n\n"; $message_part = ""; foreach ($paths as $path) < $fp = fopen($path, "r"); if (!$fp) < echo "Файл $path не может быть прочитан"; exit(); >$file = fread($fp, filesize($path)); fclose($fp); $message_part .= "--$boundary\n"; $message_part .= "Content-Type: application/octet-stream\n"; $message_part .= "Content-Transfer-Encoding: base64\n"; $message_part .= "Content-Disposition: attachment; filename = \"" . $path . "\"\n\n"; $message_part .= chunk_split(base64_encode($file)) . "\n"; > $multipart .= $message_part . "--$boundary--\n"; if (!mail($to, $form_subject, $multipart, $headers)) < echo "К сожалению, письмо не отправлено"; exit(); >>
Надеюсь, вам понравилась данная информация. Если вам интересна тема web-разработки, то можете следить за выходом новых статей в Telegram.