Селектори для пошуку DOM-елементів
Селектори DOM - це способи знаходити елементи на сторінці за допомогою JavaScript. Без них неможливо взаємодіяти з HTML: спершу треба отримати елемент, щоб щось із ним зробити (змінити текст, стиль, видалити, додати обробник події тощо).
Теорія
TL;DR
- Селектор - це спосіб указати, який саме елемент у DOM треба вибрати: за
id, тегом, класом, атрибутом або повноцінним CSS-селектором. getElementByIdповертає один елемент,getElementsByClassNameіgetElementsByTagNameповертають HTMLCollection.querySelectorповертає перший збіг за CSS-селектором,querySelectorAll- усі збіги у вигляді NodeList.- Колекції
getElementsBy...живі: новий елемент у DOM з'являється в них автоматично. NodeList відquerySelectorAllстатичний. - Пошук можна звужувати: у знайденого елемента теж є
querySelectorіquerySelectorAll.
Швидкий приклад
// HTML: <ul class="menu"><li>Головна</li><li class="active">Профіль</li></ul>
const menu = document.querySelector('.menu'); // перший збіг
const items = menu.querySelectorAll('li'); // пошук усередині menu
const active = document.querySelector('.menu li.active');
console.log(items.length); // 2
console.log(active.textContent); // ПрофільОсновні методи вибору елементів
| Метод | Що повертає | Що приймає | Приклад |
|---|---|---|---|
getElementById(id) | один елемент | id (без #) | document.getElementById("header") |
getElementsByClassName(class) | HTMLCollection (масивоподібна) | ім'я класу (без .) | document.getElementsByClassName("menu") |
getElementsByTagName(tag) | HTMLCollection | ім'я тега | document.getElementsByTagName("p") |
querySelector(selector) | перший елемент | CSS-селектор | document.querySelector(".menu li") |
querySelectorAll(selector) | NodeList (усі відповідні) | CSS-селектор | document.querySelectorAll("div > p") |
Детально про кожен метод
document.getElementById() знаходить один елемент за атрибутом id.
<h1 id="title">Привіт!</h1>const el = document.getElementById('title');
console.log(el.textContent); // Привіт!Плюс: дуже швидкий. Мінуси: працює тільки за id і повертає лише один елемент.
document.getElementsByClassName() шукає всі елементи із заданим класом.
<p class="text">Перший</p>
<p class="text">Другий</p>const els = document.getElementsByClassName('text');
console.log(els.length); // 2Плюс: швидкий, підтримується всюди. Мінус: повертає HTMLCollection, яку треба перетворити на масив (Array.from), щоб скористатися forEach.
document.getElementsByTagName() знаходить усі елементи за тегом.
const paragraphs = document.getElementsByTagName('p');Повертає живу колекцію: якщо в DOM з'явиться новий <p>, він додасться до неї автоматично.
document.querySelector() використовує CSS-селектори і повертає перший знайдений елемент.
const item = document.querySelector('.menu li.active');Плюс: універсальний, підтримує всі можливості CSS-селекторів. Мінус: повертає лише один елемент.
document.querySelectorAll() повертає всі елементи, що відповідають CSS-селектору.
const items = document.querySelectorAll('.menu li');
items.forEach((li) => console.log(li.textContent));Плюс: повертає NodeList, у якого одразу є forEach(). Мінус: колекція не оновлюється автоматично, на відміну від getElementsBy....
Типи селекторів (як у CSS)
| Селектор | Приклад | Опис |
|---|---|---|
| За тегом | "div" | усі <div> |
| За класом | ".item" | усі елементи з класом item |
За id | "#header" | елемент з id="header" |
| За атрибутом | "[type='text']" | елементи з type="text" |
| Нащадки | "ul li" | усі <li> всередині <ul> |
| Прямі нащадки | "ul > li" | тільки ті, що на першому рівні вкладеності |
| Комбіновані | "div.item.active" | <div class="item active"> |
| Псевдокласи | "li:first-child", "input:checked" | специфічні стани |
Коли що використовувати
| Мета | Краще використати |
|---|---|
Швидко отримати елемент за id | getElementById() |
| Знайти за класом або тегом | getElementsByClassName() / getElementsByTagName() |
| Складний пошук (як у CSS) | querySelector() / querySelectorAll() |
| Колекція, що сама оновлюється | getElementsBy... |
| Разовий статичний список | querySelectorAll() |
Приклад комплексного пошуку. HTML:
<div class="card">
<h2 class="title">Заголовок</h2>
<p class="desc">Опис</p>
</div>JavaScript:
const card = document.querySelector('.card');
const title = card.querySelector('.title');
const desc = card.querySelector('.desc');
console.log(title.textContent); // "Заголовок"Порада: за замовчуванням беріть querySelector / querySelectorAll, це універсальний і сучасний спосіб, який працює з будь-якими CSS-селекторами. getElementById та getElementsByClassName корисні там, де потрібна максимальна продуктивність (старий код або тисячі елементів).
Робота зі знайденими елементами
Після того як елемент знайдено, з ним можна зробити майже що завгодно:
const el = document.querySelector('#myDiv');
el.textContent = 'Новий текст'; // змінити вміст
el.style.color = 'red'; // змінити стиль
el.classList.add('active'); // додати клас
el.addEventListener('click', onClick); // повісити обробникКоротко про повернені значення:
| Метод | Повертає | Особливості |
|---|---|---|
getElementById(id) | один елемент | швидкий, унікальний id |
getElementsByClassName() | HTMLCollection | динамічна колекція |
getElementsByTagName() | HTMLCollection | пошук за тегом |
querySelector() | перший елемент | CSS-селектор |
querySelectorAll() | NodeList | усі відповідні елементи |
Типові помилки
- Передавати
#або.туди, де їх не чекають.getElementById('#title')повернеnull: цей метод приймає чистийid. А отquerySelector('#title')вимагає саме#. - Викликати
forEachна HTMLCollection. УgetElementsByClassName/getElementsByTagNameнемаєforEach; спершу зробітьArray.from(els)або використайтеquerySelectorAll. - Не перевіряти результат на
null.querySelectorіgetElementByIdповертаютьnull, якщо нічого не знайдено, і звернення до.textContentодразу впаде з помилкою. - Забувати про живі колекції. Цикл по HTMLCollection, усередині якого ви видаляєте елементи, пропускає частину з них, бо колекція змінюється на льоту.
- Шукати елементи до того, як розібрано HTML. Скрипт у
<head>безdeferвиконається раніше за розмітку, і селектор нічого не знайде. - Шукати завжди від
document. Якщо ви вже маєте контейнер, викликайтеcard.querySelector('.title'): це і швидше, і точніше.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.