Практически на каждом проекте есть потребность в отправке данных на почту. Некоторые разработчики реализуют этот функционал через стандартный компонент отправки, некоторые прибегают к помощи Веб форм. Ну а я по старинке))))
Мне так проще и функциональней. Функционал можно накрутить любой и он гибок.
В качестве примера распишу полный вариант реализации отправки данных в инфоблок и на почту.
Верстка формы HTML
<div class="form">
<h1>Форма связи</h1>
<div class="form__success">
Сообщение отправлено!
<br>
Наши специалисты свяжутся с Вами в ближайшее время
</div>
<form enctype="multipart/form-data">
<input class="clean form__field" type="text" name="name" placeholder="Имя" value="">
<input class="clean form__field" type="email" name="email" placeholder="Email *" value="">
<textarea class="clean form__field" rows="3" name="text" placeholder="Текст сообщения"></textarea>
<input class="clean form__file" type="file" name="file[]" multiple="multiple">
<input hidden type="text" name="url" value="<?=explode('?', $_SERVER['REQUEST_URI'])[0]?>">
<button name="send" type="submit">Отправить</button>
</form>
</div>
Отправка из формы в файл обработки JavaScript / AJAX
window.onload = function () {
// функция очистки полей формы, после отправки
function cleanForm() {
// загоняем все поля в переменную
let clean = document.querySelectorAll('.clean');
//циклом проходимся по ним и обнуляем значение
for (let item of clean) {
item.value = '';
}
}
// Функция отправки формы fetch
async function postData(url= '', data = {}) {
const response = await fetch(url, {
method: "POST",
body: data
});
return await response.json();
}
// собираем все формы со страницы в переменную
let forms = document.querySelectorAll('.form form');
// каждой форме присваиваем действие при отправке
for (let form of forms) {
// при отправке формы любым способом
form.addEventListener('submit', function (event) {
// запрещаем стандартное действие
event.preventDefault();
// создаем объект новый
let data = new FormData(form);
// передаем в функцию fetch данные и получаем результат
postData('send.php', data).then((data) => {
// обработка ответа от сервера
// переменная обращения к этой форме
let thisForm = event.target;
// если ошибок нет
if (data.error === '') {
// показываем благодарственное сообщение и чистим форму
thisForm.parentElement.classList.add('success');
cleanForm();
console.log(data.success);
}
else {
// если есть ошибки
console.log(data);
// перебираем ответ и соответствующим полям присваиваем error
for (let field in data) {
// поле с ошибкой
let errorField = thisForm.querySelector(`[name=${field}]`);
if (errorField) {
// на время присваиваем полю класс для визуализации
errorField.classList.add('error');
setTimeout(function (){errorField.classList.remove('error');}, 3000)
}
}
}
})
})
}
};
window.onload = function () {
// отправка
$(document).on('submit', 'form', function (e) {
// отменяем стандартные действия
e.preventDefault();
// переменные для сокращения кода
const formContainer = $(this).parent()[0];
const thisForm = e.target;
// тело формы
let data = new FormData(this);
// запрос
$.ajax({
url: 'send.php',
type: 'post',
contentType: false,
processData: false,
dataType: 'json',
data: data,
success: function (data) {
if (data.error === '') {
// если нет ошибок
// показываем панель спасибо
// чистим поля
$(formContainer).addClass('success');
$(thisForm).find('.clean').val('');
console.log(data.success);
} else {
// если есть ошибка
console.log(data);
// циклом перебираем ответ, находим в каких полях ошибки и выделяем их
for (let field in data) {
// переменная полем
let errorField = $(thisForm).find(`[name=${field}]`);
// если поле существует
if (errorField.length) {
// временно добавляем и убираем класс ошибки
errorField.addClass('error');
setTimeout(function () { errorField.removeClass('error'); }, 3000);
}
}
}
},
// выводим другие ошибки
error: function (data) {
console.log('error');
console.log(data);
}
});
});
};
Файл обработки на сервере
<? require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
use Bitrix\Main\Mail\Event;
// перед присвоением в переменную, проверяем есть ли данные
if (!empty($_POST["name"])) $name = $_POST['name'];
//if (!empty($_POST["email"])) $email = $_POST['email'];
if (!empty($_POST["text"])) $text = $_POST['text'];
if (!empty($_POST["url"])) $url = $_POST['url'];
/*** Проверка данных ***/
// валидация почты
if (filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)) {
$email = $_POST['email'];
} else {
$result['email'] = 'Введите адрес электронной почты';
}
// Отправка данных
if ($email) {
// подключаем модуль инфоблоков
CModule::IncludeModule('iblock');
// инициализируем
$elem = new CIBlockElement;
// создаем пустой массив и собираем в него поля
$PROP = [];
$PROP['NAME'] = $name;
$PROP['EMAIL'] = $email;
$PROP['TEXT'] = $text;
$PROP['URL'] = $url;
// пустой массив для сбора ид файлов
$arF = [];
// проверяем есть ли файлы
if ($_FILES['file']) {
// количество файлов
$count = count($_FILES['file']['name']);
// сохраняем файлы и получаем ид
for ($i = 0; $i < $count; $i++) {
$arIMAGE["name"] = $_FILES['file']['name'][$i];
$arIMAGE["size"] = $_FILES['file']['size'][$i];
$arIMAGE["tmp_name"] = $_FILES['file']['tmp_name'][$i];
$arIMAGE["type"] = $_FILES['file']['type'][$i];
$arIMAGE["MODULE_ID"] = "vote";
$fid = CFile::SaveFile($arIMAGE, "vote");
$arF[] = $fid;
}
}
// все ид файлов присваиваем свойству
$PROP['FILES'] = $arF;
// настройки
$arLoadProductArray = array(
"MODIFIED_BY" => 1,
"IBLOCK_SECTION_ID" => false, // элемент лежит в корне раздела
"IBLOCK_ID" => 8, // Ид инфоблока
"PROPERTY_VALUES" => $PROP, // массив со свойствами
"NAME" => $email, // имя записи
"ACTIVE" => "Y",
);
// сохраняем
$PRODUCT_ID = $elem->Add($arLoadProductArray);
// отправка средствами Битрикс
Event::send(array(
"EVENT_NAME" => "SEND",
"LID" => "s1",
"C_FIELDS" => array(
"AUTHOR" => $name,
"AUTHOR_EMAIL" => $email,
"TEXT" => $text,
"URL" => $url,
),
"FILE" => $arF,
));
if($arF)
CFile::Delete($arF);
// если отправка успешна
$result['error'] = "";
$result['success'] = "Сообщение N$PRODUCT_ID отправлено";
} else {
$result['error'] = 'Сообщение не отправлено';
}
/*** Возврат результата отправки ***/
header('Content-Type: application/json');
echo json_encode($result);
Минимальная стилизация SCSS / CSS
.form {
position: relative;
h1 {
font-size: 50px;
line-height: 150%;
margin-bottom: 20px;
text-align: center;
}
form {
display: flex;
flex-direction: column;
position: relative;
}
&__success {
display: none;
z-index: -5;
opacity: 0;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding: 15px;
align-items: center;
justify-content: center;
text-align: center;
color: green;
font-size: 30px;
line-height: 140%;
background-color: white;
}
&.success {
.form__success {
display: flex;
opacity: 1;
z-index: 5;
}
}
&__file {
margin-bottom: 20px;
font-size: 18px;
}
&__field {
border: 1px black solid;
margin-bottom: 20px;
padding: 5px 15px;
font-size: 18px;
line-height: 150%;
border-radius: 5px;
max-width: 100%;
&.error {
border-color: red;
color: red;
&::-webkit-input-placeholder {
color: red;
}
&::-moz-placeholder {
color: red;
opacity: 1;
}
&::placeholder {
color: red;
}
}
}
button {
width: 150px;
height: 45px;
border-radius: 5px;
font-size: 18px;
}
}
.form {
position: relative;
}
.form h1 {
font-size: 50px;
line-height: 150%;
margin-bottom: 20px;
text-align: center;
}
.form form {
display: flex;
flex-direction: column;
position: relative;
}
.form__success {
display: none;
z-index: -5;
opacity: 0;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding: 15px;
align-items: center;
justify-content: center;
text-align: center;
color: green;
font-size: 30px;
line-height: 140%;
background-color: white;
}
.form.success .form__success {
display: flex;
opacity: 1;
z-index: 5;
}
.form__file {
margin-bottom: 20px;
font-size: 18px;
}
.form__field {
border: 1px black solid;
margin-bottom: 20px;
padding: 5px 15px;
font-size: 18px;
line-height: 150%;
border-radius: 5px;
max-width: 100%;
}
.form__field.error {
border-color: red;
color: red;
}
.form__field.error::-webkit-input-placeholder {
color: red;
}
.form__field.error::-moz-placeholder {
color: red;
opacity: 1;
}
.form__field.error::placeholder {
color: red;
}
.form button {
width: 150px;
height: 45px;
border-radius: 5px;
font-size: 18px;
}
Настройка типа события
Настройка почтового шаблона
Комментарии