Стилизация Input File
Сегодня будем стилизовать input type file. Т.к. стилизация тесно связана с обработкой input file на фронтенде, мы так же рассмотрим, как обработать выбранный файл и отправить на сервер. Скрипт будет работать для множества форм с возможностью не только загрузить файл при клике на кнопку, но так же перетаскиванием файла (drag-and-drop) в область загрузки. Если вам не нужен тот или иной функционал, вы легко сможете удалить часть кода.
Содержание:
- кнопка «Прикрепить файл»
- drag-and-drop загрузка файлов
- совместное использование кнопки «Прикрепить файл» и Drag-and-drop
- отправка множества input file multiple (PHP)
1. Стилизация input type file
1.1 Кнопка «Прикрепить файл» — HTML, CSS
Сначала нам необходимо создать html-разметку.
- multiple — данный атрибут необходим, если вы хотите разрешить отправку более одного файла;
- accept — в данный атрибут запишите типы файлов (MIME-типы), которые разрешены для выбора.
<form>
<input type="text" name="Ваше имя">
<input type="email" name="E-mail">
<div class="upload-file__wrapper">
<input
type="file"
name="files[]"
id="upload-file__input_1"
class="upload-file__input"
accept=".jpg, .jpeg, .png, .gif, .bmp, .doc, .docx, .xls, .xlsx, .txt, .tar, .zip, .7z, .7zip"
multiple
>
<label class="upload-file__label" for="upload-file__input_1">
<svg class="upload-file__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M286 384h-80c-14.2 1-23-10.7-24-24V192h-87.7c-17.8 0-26.7-21.5-14.1-34.1L242.3 5.7c7.5-7.5 19.8-7.5 27.3 0l152.2 152.2c11.6 11.6 3.7 33.1-13.1 34.1H320v168c0 13.3-10.7 24-24 24zm216-8v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-23-23V366c0-13.3 10.7-24 24-24h136v8c0 31 24.3 56 56 56h80c30.9 0 55-26.1 57-55v-8h135c13.3 0 24 10.6 24 24zm-124 88c0-11-9-20-19-20s-19 9-20 20 9 19 20 20 21-9 20-20zm64 0c0-12-9-20-20-20s-20 9-19 20 9 20 20 20 21-9 20-20z"></path>
</svg>
<span class="upload-file__text">Прикрепить файл</span>
</label>
</div>
<button type="submit">Отправить</button>
</form>
Скроем 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 {
border: 2px dashed #58862D;
}
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 Мб
if (file.size > 5 * 1024 * 1024) {
alert("Файл должен быть не более 5 МБ.");
return;
}
// Показ загружаемых файлов
if (file && file.length > 1) {
if ( file.length <= 4 ) {
textSelector.textContent = `Выбрано ${file.length} файла`;
}
if ( file.length > 4 ) {
textSelector.textContent = `Выбрано ${file.length} файлов`;
}
} 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
<form>
<input type="text" name="Ваше имя">
<input type="email" name="E-mail">
<div class="upload-file__wrapper">
<input type="file" name="files" id="upload-file__input" class="upload-file__input" multiple accept="image/jpeg,image/png,image/gif">
<label class="upload-file__label" for="upload-file__input">
<svg class="upload-file__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M286 384h-80c-14.2 1-23-10.7-24-24V192h-87.7c-17.8 0-26.7-21.5-14.1-34.1L242.3 5.7c7.5-7.5 19.8-7.5 27.3 0l152.2 152.2c11.6 11.6 3.7 33.1-13.1 34.1H320v168c0 13.3-10.7 24-24 24zm216-8v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-23-23V366c0-13.3 10.7-24 24-24h136v8c0 31 24.3 56 56 56h80c30.9 0 55-26.1 57-55v-8h135c13.3 0 24 10.6 24 24zm-124 88c0-11-9-20-19-20s-19 9-20 20 9 19 20 20 21-9 20-20zm64 0c0-12-9-20-20-20s-20 9-19 20 9 20 20 20 21-9 20-20z">
</path>
</svg>
<span class="upload-file__text">Прикрепить файл</span>
</label>
</div>
<button type="submit">Отправить</button>
</form>
Улучшим юсабилити путём добавления стилей для 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 {
border: 2px dashed #388e3c;
}
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 <= 4) {
dropZoneText.textContent = `Выбрано ${uploadDragFiles.length} файла`;
} else {
dropZoneText.textContent = `Выбрано ${uploadDragFiles.length} файлов`;
}
} 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 <= 4; i++) { // сюда будем помещать drug-&-drop файлы (4)
window["uploadDragFiles_"+i] = new Object();
}
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 Мб
if (file.size > 5 * 1024 * 1024) {
alert("Файл должен быть не более 5 МБ.");
return;
}
// Показ загружаемых файлов
if (file && fileList.length > 1) {
if (fileList.length <= 4) {
textSelector.textContent = `Выбрано ${fileList.length} файла`;
} else {
textSelector.textContent = `Выбрано ${fileList.length} файлов`;
}
} 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 <= 4) {
dropZoneText.textContent = `Выбрано ${uploadDragFiles.length} файла`;
} else {
dropZoneText.textContent = `Выбрано ${uploadDragFiles.length} файлов`;
}
} 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 на почту.
<?php
$project_name = trim($_POST["project_name"]);
$admin_email = trim($_POST["admin_email"]);
$form_subject = trim($_POST["form_subject"]);
$file_attach = array();
// Если поле выбора вложения не пустое - закачиваем его на сервер
if (!empty($_FILES)) {
foreach ($_FILES["files"]["name"] as $key => $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) ? "<tr>" : "<tr style='background-color: #f8f8f8;'>") . "
<td style='padding: 10px; border: #e9e9e9 1px solid;'><b>$key</b></td>
<td style='padding: 10px; border: #e9e9e9 1px solid;'>$value</td>
</tr>";
}
}
$message = '<table style="width: 100%;">
<tr>
<td style="padding:10px; border:#e9e9e9 1px solid; text-align:center" colspan="2">
<big>$project_name</big>. $form_subject
</td>
</tr>
' . $message . '
</table>';
// Отправляем сообщение
if (empty($file_attach)) {
$headers = "MIME-Version: 1.0" . PHP_EOL .
"Content-Type: text/html; charset=utf-8" . PHP_EOL .
"From: " . $project_name . " <" . $admin_email . ">" . 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.
Поделиться с друзьями:
Статьи из данной категории:
Комментарии (3)
- Марат
- Андрей
- Only to top