Формы и делегирование
Формы
Форма — это <form> с полями и кнопкой. Когда пользователь нажимает кнопку или Enter в поле,
происходит событие submit, и браузер по умолчанию отправляет форму и перезагружает страницу.
В современных сайтах это почти всегда отменяют и обрабатывают данные в JavaScript:
const form = document.querySelector("#signup");
form.addEventListener("submit", (e) => {
e.preventDefault(); // без перезагрузки
const name = form.querySelector("#name").value.trim();
console.log("Регистрируем", name);
form.reset(); // очистить все поля формы
});
Слушай именно submit на форме, а не click на кнопке: так сработают и кнопка, и Enter.
Проверка полей
Перед отправкой данные проверяют и показывают ошибку рядом с полем:
form.addEventListener("submit", (e) => {
e.preventDefault();
const age = Number(form.querySelector("#age").value);
const error = form.querySelector(".error");
if (!Number.isInteger(age) || age < 1 || age > 120) {
error.textContent = "Возраст — целое число от 1 до 120";
return;
}
error.textContent = "";
console.log("Всё верно");
});
trim() убирает пробелы по краям — иначе строка из одних пробелов прошла бы проверку «не пусто».
Всплытие событий
Событие, случившееся на элементе, потом всплывает вверх: срабатывают обработчики у родителя, у
его родителя и так до document. Клик по кнопке внутри <div id="toolbar"> — это ещё и клик по
#toolbar, и по body.
e.target — самый глубокий элемент, на котором всё началось, а e.currentTarget — тот, чей
обработчик сейчас выполняется.
Делегирование
Вместо обработчика на каждой из ста кнопок вешают один — на общего родителя — и в нём смотрят, по какой кнопке кликнули:
document.querySelector("#menu").addEventListener("click", (e) => {
const btn = e.target.closest("button");
if (!btn) return; // кликнули мимо кнопок
console.log("Действие:", btn.dataset.action);
});
closest(селектор) ищет ближайший подходящий элемент, начиная с самого e.target и поднимаясь
вверх. Это важно: если внутри кнопки есть <span> или иконка, e.target будет ими, а closest
всё равно найдёт кнопку.
Плюсы делегирования:
- один обработчик вместо многих;
- элементы, добавленные позже (новые дела в списке), работают сами — их обработчик уже на родителе;
- после
render(), который пересоздаёт всеli, ничего не нужно подписывать заново.
Состояние + render + делегирование
Так устроены почти все небольшие интерфейсы на чистом JavaScript:
let items = []; // 1. данные — единственный источник правды
function render() { // 2. страница строится только из данных
// очистить и создать элементы по items
}
list.addEventListener("click", (e) => { // 3. события меняют данные…
// найти элемент через closest, изменить items
render(); // …и перерисовывают страницу
});
Никогда не храни важное «только в HTML» (например, сделано ли дело — лишь в классе элемента): после перерисовки оно потеряется. Данные — в массиве, HTML — их отражение.
Итог
submit+e.preventDefault()— обработать форму без перезагрузки,form.reset()— очистить.- События всплывают: клик по кнопке — это клик и по всем её родителям.
- Делегирование: один обработчик на родителе +
e.target.closest(...). - Данные в переменных →
render()строит страницу → события меняют данные и вызываютrender().