Форма регистрации на GitHub проверяет доступность никнейма в реальном времени — пока ты печатаешь. Форма оплаты на Ozon мгновенно показывает ошибку если ввести неверный CVV. Форма поиска в Avito фильтрует результаты при каждом символе. Всё это — обработка событий форм через JavaScript.
HTML-форма по умолчанию перезагружает страницу при отправке. JavaScript позволяет отменить перезагрузку, получить данные, валидировать их и отправить через fetch без перезагрузки страницы.
// input — срабатывает при КАЖДОМ изменении (каждый символ)
input.addEventListener('input', (e) => {
console.log(e.target.value) // текущее значение
validateField(e.target)
})
// change — срабатывает при потере фокуса или выборе в select
input.addEventListener('change', handler)
// focus / blur — получение/потеря фокуса
input.addEventListener('focus', () => input.classList.add('focused'))
input.addEventListener('blur', () => validateOnBlur(input))
// submit — отправка формы
form.addEventListener('submit', (e) => {
e.preventDefault() // ОБЯЗАТЕЛЬНО — отменяет перезагрузку страницы
handleSubmit(e)
})input.value // текст в поле
checkbox.checked // boolean для чекбоксов
select.value // выбранный вариант
textarea.value // текст в textareaform.addEventListener('submit', (e) => {
e.preventDefault()
const data = new FormData(form)
data.get('email') // значение поля с name="email"
data.getAll('tags') // массив для multiple-select
// Преобразовать в обычный объект
const obj = Object.fromEntries(data)
})input.validity.valid // true/false
input.validity.valueMissing // required поле пустое
input.validity.typeMismatch // неправильный тип (email, url)
input.validity.tooShort // короче minlength
input.setCustomValidity('Логин уже занят') // установить ошибку
input.setCustomValidity('') // сбросить ошибку
input.checkValidity() // true/falsefunction validateEmail(value) {
if (!value.trim()) return 'Email обязателен'
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return 'Некорректный email'
return null // нет ошибки
}
emailInput.addEventListener('blur', () => {
const error = validateEmail(emailInput.value)
if (error) showFieldError(emailInput, error)
else clearFieldError(emailInput)
})Ошибка 1: забыли e.preventDefault() — страница перезагружается
// Нет e.preventDefault() — страница перезагрузится!
form.addEventListener('submit', (e) => {
sendData(new FormData(form))
})
// Правильно
form.addEventListener('submit', (e) => {
e.preventDefault() // всегда первым
sendData(new FormData(form))
})Ошибка 2: валидация только на submit — плохой UX
// Пользователь узнаёт об ошибке только после нажатия кнопки
form.addEventListener('submit', validate)
// Лучше — валидируем при потере фокуса (blur)
inputs.forEach(input => {
input.addEventListener('blur', () => validateField(input))
})Ошибка 3: data.get() возвращает строку
const data = new FormData(form)
const age = data.get('age') // '25' — строка, не число!
// Правильно
const age = Number(data.get('age'))
const price = parseFloat(data.get('price'))Симуляция обработки и валидации формы регистрации
// Симуляция FormData через объект
function mockFormData(fields) {
return {
data: Object.assign({}, fields),
get(name) { return this.data[name] ?? null },
has(name) { return name in this.data },
set(name, value) { this.data[name] = value },
entries() { return Object.entries(this.data) }
}
}
// Валидация формы регистрации (GitHub-подобный сервис)
function validateRegistration(formData) {
const errors = {}
const username = (formData.get('username') || '').trim()
const email = (formData.get('email') || '').trim()
const password = formData.get('password') || ''
if (!username) {
errors.username = 'Имя пользователя обязательно'
} else if (username.length < 3) {
errors.username = 'Минимум 3 символа'
} else if (!/^[a-zA-Z0-9-]+$/.test(username)) {
errors.username = 'Только латиница, цифры и дефис'
}
if (!email) {
errors.email = 'Email обязателен'
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
errors.email = 'Некорректный формат email'
}
if (!password) {
errors.password = 'Пароль обязателен'
} else if (password.length < 8) {
errors.password = 'Минимум 8 символов'
} else if (!/\d/.test(password)) {
errors.password = 'Пароль должен содержать хотя бы одну цифру'
}
return { valid: Object.keys(errors).length === 0, errors }
}
// Тест 1: невалидные данные
const badData = mockFormData({ username: 'ab', email: 'не-email', password: 'abc' })
const r1 = validateRegistration(badData)
console.log(r1.valid) // false
console.log(Object.keys(r1.errors)) // ['username', 'email', 'password']
// Тест 2: валидные данные
const goodData = mockFormData({ username: 'alice-dev', email: 'alice@github.com', password: 'secure123' })
const r2 = validateRegistration(goodData)
console.log(r2.valid) // true
console.log(r2.errors) // {}
// Тест 3: частично верные данные
const partialData = mockFormData({ username: 'bob', email: 'bob@mail.ru', password: 'nodigits' })
const r3 = validateRegistration(partialData)
console.log(r3.valid) // false
console.log(r3.errors.password) // 'Пароль должен содержать хотя бы одну цифру'Форма регистрации на GitHub проверяет доступность никнейма в реальном времени — пока ты печатаешь. Форма оплаты на Ozon мгновенно показывает ошибку если ввести неверный CVV. Форма поиска в Avito фильтрует результаты при каждом символе. Всё это — обработка событий форм через JavaScript.
HTML-форма по умолчанию перезагружает страницу при отправке. JavaScript позволяет отменить перезагрузку, получить данные, валидировать их и отправить через fetch без перезагрузки страницы.
// input — срабатывает при КАЖДОМ изменении (каждый символ)
input.addEventListener('input', (e) => {
console.log(e.target.value) // текущее значение
validateField(e.target)
})
// change — срабатывает при потере фокуса или выборе в select
input.addEventListener('change', handler)
// focus / blur — получение/потеря фокуса
input.addEventListener('focus', () => input.classList.add('focused'))
input.addEventListener('blur', () => validateOnBlur(input))
// submit — отправка формы
form.addEventListener('submit', (e) => {
e.preventDefault() // ОБЯЗАТЕЛЬНО — отменяет перезагрузку страницы
handleSubmit(e)
})input.value // текст в поле
checkbox.checked // boolean для чекбоксов
select.value // выбранный вариант
textarea.value // текст в textareaform.addEventListener('submit', (e) => {
e.preventDefault()
const data = new FormData(form)
data.get('email') // значение поля с name="email"
data.getAll('tags') // массив для multiple-select
// Преобразовать в обычный объект
const obj = Object.fromEntries(data)
})input.validity.valid // true/false
input.validity.valueMissing // required поле пустое
input.validity.typeMismatch // неправильный тип (email, url)
input.validity.tooShort // короче minlength
input.setCustomValidity('Логин уже занят') // установить ошибку
input.setCustomValidity('') // сбросить ошибку
input.checkValidity() // true/falsefunction validateEmail(value) {
if (!value.trim()) return 'Email обязателен'
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return 'Некорректный email'
return null // нет ошибки
}
emailInput.addEventListener('blur', () => {
const error = validateEmail(emailInput.value)
if (error) showFieldError(emailInput, error)
else clearFieldError(emailInput)
})Ошибка 1: забыли e.preventDefault() — страница перезагружается
// Нет e.preventDefault() — страница перезагрузится!
form.addEventListener('submit', (e) => {
sendData(new FormData(form))
})
// Правильно
form.addEventListener('submit', (e) => {
e.preventDefault() // всегда первым
sendData(new FormData(form))
})Ошибка 2: валидация только на submit — плохой UX
// Пользователь узнаёт об ошибке только после нажатия кнопки
form.addEventListener('submit', validate)
// Лучше — валидируем при потере фокуса (blur)
inputs.forEach(input => {
input.addEventListener('blur', () => validateField(input))
})Ошибка 3: data.get() возвращает строку
const data = new FormData(form)
const age = data.get('age') // '25' — строка, не число!
// Правильно
const age = Number(data.get('age'))
const price = parseFloat(data.get('price'))Симуляция обработки и валидации формы регистрации
// Симуляция FormData через объект
function mockFormData(fields) {
return {
data: Object.assign({}, fields),
get(name) { return this.data[name] ?? null },
has(name) { return name in this.data },
set(name, value) { this.data[name] = value },
entries() { return Object.entries(this.data) }
}
}
// Валидация формы регистрации (GitHub-подобный сервис)
function validateRegistration(formData) {
const errors = {}
const username = (formData.get('username') || '').trim()
const email = (formData.get('email') || '').trim()
const password = formData.get('password') || ''
if (!username) {
errors.username = 'Имя пользователя обязательно'
} else if (username.length < 3) {
errors.username = 'Минимум 3 символа'
} else if (!/^[a-zA-Z0-9-]+$/.test(username)) {
errors.username = 'Только латиница, цифры и дефис'
}
if (!email) {
errors.email = 'Email обязателен'
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
errors.email = 'Некорректный формат email'
}
if (!password) {
errors.password = 'Пароль обязателен'
} else if (password.length < 8) {
errors.password = 'Минимум 8 символов'
} else if (!/\d/.test(password)) {
errors.password = 'Пароль должен содержать хотя бы одну цифру'
}
return { valid: Object.keys(errors).length === 0, errors }
}
// Тест 1: невалидные данные
const badData = mockFormData({ username: 'ab', email: 'не-email', password: 'abc' })
const r1 = validateRegistration(badData)
console.log(r1.valid) // false
console.log(Object.keys(r1.errors)) // ['username', 'email', 'password']
// Тест 2: валидные данные
const goodData = mockFormData({ username: 'alice-dev', email: 'alice@github.com', password: 'secure123' })
const r2 = validateRegistration(goodData)
console.log(r2.valid) // true
console.log(r2.errors) // {}
// Тест 3: частично верные данные
const partialData = mockFormData({ username: 'bob', email: 'bob@mail.ru', password: 'nodigits' })
const r3 = validateRegistration(partialData)
console.log(r3.valid) // false
console.log(r3.errors.password) // 'Пароль должен содержать хотя бы одну цифру'Напиши функцию validateForm(data) для формы настроек профиля. Принимает объект { name, email, password }. Правила: name — минимум 2 символа; email — содержит @ и точку после @; password — минимум 8 символов, хотя бы одна цифра И хотя бы одна заглавная буква. Возвращает { valid: boolean, errors: Record<string, string> }.
Email: !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(data.email). Заглавная буква в пароле: !/[A-Z]/.test(data.password). Проверь порядок условий: сначала длина, потом цифра, потом заглавная.