Управление содержимым и поведением страниц через JavaScript
Основные способы работы JavaScript с DOM и событиями на странице
Современный и эффективный подход включает использование методов querySelector, querySelectorAll и addEventListener. Это даёт гибкость выбора элементов через CSS-селекторы и позволяет назначать несколько обработчиков на одно событие.
// Выбор элемента по классу
const button = document.querySelector('.btn');
button.textContent = 'Нажми меня';
// Обработчик клика
button.addEventListener('click', () => {
alert('Кнопка нажата');
});Javascript страницы (javascript на страницах)
При таком подходе код остаётся читаемым, легко поддерживается, а обработчики не мешают друг другу.
Возможные проблемы:
- Неправильный селектор приведёт к
null. Следует проверять существование элемента. - Обработчики на большое количество однотипных элементов (например, кнопки в списке) могут снижать производительность. В таких случаях применяют делегирование событий (см. варианты ниже).
Решение: перед использованием элемента убедиться, что он найден, а для множества элементов использовать делегирование на родительском контейнере.
Как изменить содержимое элемента с помощью старого метода getElementById и innerHTML?
// HTML: <div id="output"></div>
const div = document.getElementById('output');
div.innerHTML = '<strong>Новый текст</strong>';кнопки js (кнопки в javascript)
Метод innerHTML перезаписывает содержимое вместе с разметкой. Он быстр, но требует осторожности.
- Медленнее по сравнению с
textContentиз-за парсинга HTML. - Уязвимость XSS при вставке пользовательского ввода. Никогда не передавайте непроверенные данные.
- При перезаписи теряются все ранее добавленные обработчики событий внутри элемента.
Рекомендация: используйте textContent для чисто текстового контента, а innerHTML - только когда нужна разметка и данные полностью контролируются.
Как добавить обработчик события прямо в атрибуте HTML (onclick)?
<button onclick="handleClick()">Нажми</button>
<script>
function handleClick() {
console.log('Клик');
}
</script>
Js удалить (удаление элементов в javascript)
Такой способ прост для начинающих, но имеет серьёзные ограничения.
- Смешивание логики и разметки затрудняет поддержку.
- Нельзя назначить несколько обработчиков на одно событие - второй атрибут перезапишет первый.
- Функция должна быть глобальной, что засоряет пространство имён.
Решение: вместо атрибута используйте addEventListener в отдельном JS-файле.
Как эффективно обрабатывать события на динамически добавляемых элементах через делегирование?
// HTML: <ul id="list"></ul>
const list = document.getElementById('list');
// Генерируем новые элементы
for (let i = 0; i < 5; i++) {
const li = document.createElement('li');
li.textContent = `Элемент ${i+1}`;
list.appendChild(li);
}
// Делегирование на родителе
list.addEventListener('click', (event) => {
const target = event.target.closest('li');
if (target) {
console.log('Клик по', target.textContent);
}
});Js forms (формы в javascript)
Событие всплывает от дочернего элемента к родителю. Один обработчик на контейнере ловит клики по всем li, включая те, что будут добавлены позже.
- Неверная проверка target: без
closestможно поймать клик по самому контейнеру или вложенным элементам. - Событие может не всплыть, если оно
focusилиblur- они не всплывают, но можно использовать фазу перехвата или специальные события. - Избыточное делегирование (один обработчик на document) может замедлить страницу при огромном количестве событий.
Решение: вешать обработчик на ближайшего статического родителя и проверять event.target.closest(селектор).
Как управлять CSS-классами элемента программно?
const box = document.getElementById('box');
box.classList.add('highlight'); // добавить класс
box.classList.remove('hidden'); // удалить класс
box.classList.toggle('active'); // переключить
console.log(box.classList.contains('active')); // проверка
Методы classList - современный и безопасный способ работы с классами, не затрагивающий инлайновые стили.
- Изменение стиля через
element.style.color = 'red'менее эффективно при динамической смене тем, так как переопределяет классы. - При использовании
classNameвместоclassListможно случайно стереть существующие классы.
Рекомендуется для переключения видимости, анимаций и адаптивных состояний применять classList.
Расширенные примеры взаимодействия с DOM и событиями
1. Создание и вставка элементов в DOM
// Создаем контейнер
const container = document.createElement('div');
container.className = 'gallery';
// Цикл для создания карточек
for (let i = 0; i < 4; i++) {
const card = document.createElement('div');
card.classList.add('card');
card.dataset.index = i;
card.innerHTML = `<img src="img${i}.jpg" alt="Photo ${i}"><p>Описание ${i}</p>`;
container.appendChild(card);
}
document.body.appendChild(container);
В результате в body появляется структура: <div class="gallery"> <div class="card" data-index="0">...</div> ... </div>
Такой подход используется для динамической загрузки данных, галерей, списков товаров.
2. Анимация с requestAnimationFrame
const box = document.getElementById('animated-box');
let start = null;
function animate(timestamp) {
if (!start) start = timestamp;
const progress = (timestamp - start) / 1000; // секунды
const x = Math.min(progress * 200, 200); // движение до 200px за 1 сек
box.style.transform = `translateX(${x}px)`;
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
Элемент плавно перемещается вправо на 200 пикселей за 1 секунду.
В отличие от setInterval, анимация синхронизируется с обновлением экрана и не нагружает процессор в фоновых вкладках.
3. Обработка формы с валидацией
<form id="myForm">
<input type="email" id="email" required>
<button type="submit">Отправить</button>
</form>
<script>
document.getElementById('myForm').addEventListener('submit', (e) => {
e.preventDefault();
const email = document.getElementById('email').value.trim();
if (!email.includes('@')) {
alert('Введите корректный email');
return;
}
console.log('Отправка данных:', email);
// тут можно отправить fetch
});
</script>
При нажатии кнопки форма не перезагружает страницу, а проверяет email и выводит в консоль.
Используется для одностраничных приложений (SPA) и AJAX-форм.
4. Сохранение состояния с localStorage и восстановление
const state = {
theme: 'dark',
fontSize: 16
};
// Сохраняем
localStorage.setItem('appState', JSON.stringify(state));
// Восстанавливаем при загрузке страницы
const saved = localStorage.getItem('appState');
if (saved) {
const parsed = JSON.parse(saved);
document.body.className = parsed.theme;
document.body.style.fontSize = parsed.fontSize + 'px';
}
После обновления страницы тема и размер шрифта восстанавливаются.
Полезно для пользовательских настроек, состояния корзины, прогресса.
5. Использование dataset для хранения произвольных данных
<div id="product" data-id="123" data-price="29.99" data-currency="USD">Товар</div>
<script>
const el = document.getElementById('product');
console.log(el.dataset.id); // "123"
console.log(el.dataset.price); // "29.99"
el.dataset.currency = 'EUR'; // изменение
</script>
В консоль выведется "123" и "29.99". Атрибут data-currency станет "EUR".
Атрибуты data-* позволяют хранить метаданные прямо в HTML без костылей с дополнительными массивами. Удобно для интерфейсов с динамическими данными.