Поиск элементов

Поиск элементов — способы найти HTML-элементы в DOM-дереве для дальнейшей работы с ними: чтения, изменения, удаления или навешивания обработчиков.

Зачем нужно

Прежде чем что-то делать с элементом страницы, его нужно найти. JavaScript предоставляет несколько методов поиска — от универсальных CSS-селекторов до специализированных методов по id, классу или тегу.

Где используется

  • Получение элементов для обновления контента
  • Навешивание обработчиков событий
  • Чтение значений из форм
  • Динамическое управление DOM

Предпосылки

DOM дерево, Объекты

querySelector и querySelectorAll

// querySelector — возвращает ПЕРВЫЙ подходящий элемент или null
const header = document.querySelector('h1');
const btn = document.querySelector('.btn-primary');
const input = document.querySelector('#email');
const link = document.querySelector('a[href^="https"]');
const nested = document.querySelector('.card > .title');

// querySelectorAll — возвращает ВСЕ подходящие (NodeList)
const items = document.querySelectorAll('.list-item');
console.log(items.length); // количество найденных

// NodeList — статическая коллекция (снимок)
// Поддерживает forEach, но НЕ массив
items.forEach((item, index) => {
  console.log(index, item.textContent);
});

// Преобразование в массив для map/filter/reduce
const texts = [...items].map(el => el.textContent);
const active = Array.from(items).filter(el => el.classList.contains('active'));

// Поиск внутри элемента (не только document)
const card = document.querySelector('.card');
const title = card.querySelector('.title');  // ищет внутри card
const buttons = card.querySelectorAll('button');

getElementById

// Возвращает элемент по id или null
const app = document.getElementById('app');

// НЕ ставим #
const wrong = document.getElementById('#app'); // null!

// Работает ТОЛЬКО на document
// card.getElementById('title'); // TypeError!

// id должен быть уникальным на странице
// Если несколько элементов с одинаковым id — вернётся первый

getElementsByClassName

// Возвращает HTMLCollection (живая коллекция!)
const buttons = document.getElementsByClassName('btn');

console.log(buttons.length);    // количество
console.log(buttons[0]);        // первый элемент
console.log(buttons.item(0));   // то же самое

// Живая коллекция — обновляется при изменении DOM
const div = document.createElement('div');
div.className = 'btn';
document.body.appendChild(div);
console.log(buttons.length);    // увеличилось на 1!

// НЕ имеет forEach! Нужно преобразовать
Array.from(buttons).forEach(btn => {
  btn.style.color = 'blue';
});

// Можно искать внутри элемента
const nav = document.querySelector('nav');
const navLinks = nav.getElementsByClassName('link');

getElementsByTagName

// Возвращает HTMLCollection по тегу
const paragraphs = document.getElementsByTagName('p');
const allElements = document.getElementsByTagName('*'); // ВСЕ элементы

console.log(paragraphs.length);

// Тоже живая коллекция
// Тоже нет forEach
for (let i = 0; i < paragraphs.length; i++) {
  console.log(paragraphs[i].textContent);
}

getElementsByName

// Ищет по атрибуту name (полезно для форм)
// <input name="email" type="email">
// <input name="email" type="hidden">
const emailInputs = document.getElementsByName('email');
console.log(emailInputs.length); // 2

// Работает ТОЛЬКО на document

closest — поиск вверх по дереву

// closest ищет ближайшего предка (или сам элемент), подходящего под селектор
const btn = document.querySelector('.delete-btn');

const card = btn.closest('.card');       // ближайший .card вверх
const form = btn.closest('form');        // ближайший <form>
const section = btn.closest('section');  // ближайший <section>

// null если не найден
const table = btn.closest('table'); // null если btn не внутри таблицы

// Часто используется в делегировании событий
document.addEventListener('click', (e) => {
  const card = e.target.closest('.card');
  if (card) {
    console.log('Клик внутри карточки:', card.dataset.id);
  }
});

matches — проверка элемента

const el = document.querySelector('.btn.primary');

el.matches('.btn');          // true
el.matches('.primary');      // true
el.matches('.btn.primary');  // true
el.matches('.secondary');    // false
el.matches('button');        // true если это <button>

// Полезно для фильтрации
const allButtons = document.querySelectorAll('button');
const primary = [...allButtons].filter(btn => btn.matches('.primary'));

Сравнение методов

Метод Возвращает Коллекция forEach Контекст
querySelector Element / null document, element
querySelectorAll NodeList статическая да document, element
getElementById Element / null только document
getElementsByClassName HTMLCollection живая нет document, element
getElementsByTagName HTMLCollection живая нет document, element
getElementsByName NodeList живая да только document

Частые ошибки

1. Живая vs статическая коллекция

const liveList = document.getElementsByClassName('item');
const staticList = document.querySelectorAll('.item');

// Добавляем новый элемент
const newItem = document.createElement('div');
newItem.className = 'item';
document.body.appendChild(newItem);

// liveList.length увеличился!
// staticList.length остался прежним (снимок на момент вызова)

2. Попытка итерировать HTMLCollection напрямую

const items = document.getElementsByClassName('item');

// Ошибка: items.forEach is not a function
// items.forEach(item => item.remove());

// Решение 1: Array.from
Array.from(items).forEach(item => console.log(item));

// Решение 2: spread
[...items].forEach(item => console.log(item));

// Решение 3: for...of
for (const item of items) {
  console.log(item);
}

3. querySelectorAll возвращает NodeList, а не массив

const items = document.querySelectorAll('.item');

// Есть forEach, но нет map/filter/reduce
// items.map(el => el.id); // TypeError!

// Решение
const ids = [...items].map(el => el.id);

Практика

  1. Найди все ссылки на странице и выведи их href
  2. Найди элемент по id и измени его содержимое
  3. Используй closest для определения родительского блока по клику
  4. Сравни поведение querySelectorAll и getElementsByClassName при добавлении элемента

Связанные темы

Ресурсы