События формы: submit, input, change
submitсрабатывает при отправке формы,input— при каждом изменении значения поля,change— после завершения изменения и потери фокуса; каждое используется в своём сценарии взаимодействия с формой.
Зачем нужно
Правильный выбор между input и change влияет на производительность и UX: input нужен для мгновенной реакции (живой поиск, подсчёт символов), change — для более «тяжёлых» операций после завершения ввода. submit — единственный надёжный способ перехватить отправку формы.
Где используется
submit— отправка формы через AJAX без перезагрузки страницыinput— живой поиск, подсчёт символов, валидация в реальном времениchange— изменение настроек, смена значений<select>,<checkbox>, файловый инпут
submit
const form = document.querySelector('#login-form');
form.addEventListener('submit', async (event) => {
event.preventDefault(); // обязательно — отменяем reload
const formData = new FormData(form);
const payload = Object.fromEntries(formData);
try {
const res = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error('Ошибка авторизации');
const { token } = await res.json();
localStorage.setItem('token', token);
location.assign('/dashboard');
} catch (err) {
showFormError(err.message);
}
});
input
Срабатывает при каждом изменении значения (каждый нажатый символ):
const search = document.querySelector('#search');
const results = document.querySelector('#results');
search.addEventListener('input', async (event) => {
const query = event.target.value.trim();
if (query.length < 2) {
results.innerHTML = '';
return;
}
const data = await fetchSearch(query);
renderResults(data);
});
// Счётчик символов
const textarea = document.querySelector('#bio');
const counter = document.querySelector('#char-count');
textarea.addEventListener('input', () => {
counter.textContent = `${textarea.value.length} / 300`;
if (textarea.value.length > 300) counter.classList.add('over');
});
change
Срабатывает после завершения изменения и потери фокуса (или сразу при выборе для checkbox/select):
// Select — мгновенно при выборе
const countrySelect = document.querySelector('#country');
countrySelect.addEventListener('change', (e) => {
loadCities(e.target.value); // загружаем города для выбранной страны
});
// Checkbox — мгновенно
const darkMode = document.querySelector('#dark-mode');
darkMode.addEventListener('change', () => {
document.body.classList.toggle('dark', darkMode.checked);
localStorage.setItem('darkMode', darkMode.checked);
});
// Text input — после потери фокуса (blur)
const username = document.querySelector('#username');
username.addEventListener('change', async () => {
const available = await checkUsernameAvailability(username.value);
showAvailability(available);
});
input vs change для text-полей
const field = document.querySelector('#price');
// input: каждый символ — подходит для мгновенного отклика
field.addEventListener('input', () => {
previewTotal(field.value); // лёгкая операция
});
// change: только после blur — подходит для тяжёлых операций
field.addEventListener('change', () => {
validateAndSave(field.value); // тяжёлая операция
});
Файловый инпут
const fileInput = document.querySelector('#avatar');
fileInput.addEventListener('change', () => {
const file = fileInput.files[0];
if (!file) return;
if (file.size > 5 * 1024 * 1024) {
alert('Файл слишком большой (макс. 5 МБ)');
fileInput.value = ''; // очищаем
return;
}
const reader = new FileReader();
reader.onload = (e) => {
preview.src = e.target.result;
};
reader.readAsDataURL(file);
});
Частые ошибки
1. Забытый preventDefault в submit
form.addEventListener('submit', (e) => {
// Без e.preventDefault() — страница перезагрузится
processForm; // может не выполниться
});
2. Использование change для живого поиска
// Плохо: change срабатывает только после blur
search.addEventListener('change', performSearch); // пользователь печатает и ничего не происходит
// Хорошо: input для мгновенной реакции
search.addEventListener('input', performSearch);
3. Многократная отправка формы
// Защита от двойного клика
form.addEventListener('submit', async (e) => {
e.preventDefault();
const submitBtn = form.querySelector('[type="submit"]');
submitBtn.disabled = true;
try {
await sendData;
} finally {
submitBtn.disabled = false; // восстанавливаем в любом случае
}
});
Связанные темы
- Работа с формами через JS
- События фокуса -- focus, blur
- FormData и multipart
- _MOC DOM
- _MOC JavaScript