Управление содержимым и поведением страниц через JavaScript

Раздел: Веб-разработка -> DOM и события

Основные способы работы 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 без костылей с дополнительными массивами. Удобно для интерфейсов с динамическими данными.

JavaScript на страницах - comments

En
Javascript страницы (javascript)