Поиск элементов
Поиск элементов — способы найти HTML-элементы в DOM-дереве для дальнейшей работы с ними: чтения, изменения, удаления или навешивания обработчиков.
Зачем нужно
Прежде чем что-то делать с элементом страницы, его нужно найти. JavaScript предоставляет несколько методов поиска — от универсальных CSS-селекторов до специализированных методов по id, классу или тегу.
Где используется
- Получение элементов для обновления контента
- Навешивание обработчиков событий
- Чтение значений из форм
- Динамическое управление 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);
Практика
- Найди все ссылки на странице и выведи их
href - Найди элемент по id и измени его содержимое
- Используй
closestдля определения родительского блока по клику - Сравни поведение
querySelectorAllиgetElementsByClassNameпри добавлении элемента