JavaScript — выбор элементов DOM
Узнайте, как выбирать элементы DOM в JavaScript с помощью getElementById, querySelector, querySelectorAll, getElementsByClassName, matches и closest — с примерами и советами по применению каждого метода.
Прежде чем изменить что-либо на странице с помощью JavaScript — обновить текст, переключить класс, добавить обработчик клика — нужно сначала найти нужный элемент. Этот процесс поиска называется выбором элемента DOM. В этой главе рассматриваются все необходимые методы: что возвращает каждый из них и когда следует к нему обращаться.
Что означает «выбрать элемент»
Document Object Model (DOM) — это живое древовидное представление HTML-документа, которое строит браузер. Каждый тег становится объектом-узлом, который можно читать и изменять из JavaScript. Выбор — это процесс нахождения одного или нескольких таких узлов, чтобы сохранить ссылку на них в переменной:
const heading = document.querySelector('h1');
// `heading` now points at the real <h1> on the page.Получив такую ссылку, вы можете делать всё остальное — читать атрибуты и свойства, изменять стили, добавлять обработчики событий.
Методы выбора делятся на две группы:
- Поиск по ID / классу / тегу — быстрый; возвращает живые коллекции (за исключением
getElementById). - Поиск по CSS-селекторам (
querySelector,querySelectorAll) — гибкий; принимает любой CSS-селектор; возвращает статический результат.
Выбор одного элемента по ID: getElementById
Самый быстрый способ получить единственный элемент — обратиться к нему по уникальному id. Метод возвращает элемент или null, если элемент с таким ID не существует.
const element = document.getElementById('example');
element.textContent = 'You selected the element by its ID!';Поскольку ID должны быть уникальными, getElementById возвращает один элемент (а не коллекцию) и является наиболее прямым и быстрым способом поиска.
Если совпадений нет, getElementById возвращает null. Обращение к свойству null вызовет TypeError: Cannot read properties of null. Защититесь от этого: const el = document.getElementById('maybe'); if (el) { /* ... */ }.
Выбор по имени класса: getElementsByClassName
Этот метод возвращает живую HTMLCollection всех элементов с указанным классом. «Живая» означает, что коллекция автоматически обновляется при изменении DOM.
const elements = document.getElementsByClassName('example');
Array.from(elements).forEach((element, index) => {
element.textContent = `Element ${index + 1} changed!`;
});HTMLCollection похожа на array, но не является им, поэтому у неё нет методов forEach/map. Перед использованием этих методов преобразуйте коллекцию с помощью Array.from() (или оператора расширения [...elements]).
Поскольку коллекция живая, цикл for (let i = 0; i < c.length; i++) с удалением совпадающих элементов внутри может пропускать элементы — длина коллекции уменьшается прямо во время итерации. Сделайте снимок с помощью Array.from(), если планируете изменять DOM в процессе перебора.
Выбор по имени тега: getElementsByTagName
Выбирает все элементы с указанным именем тега и возвращает живую HTMLCollection.
const paragraphs = document.getElementsByTagName('p');
for (let i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.backgroundColor = 'yellow';
}Передайте '*', чтобы охватить все элементы страницы. Это удобно, когда нужно обработать все теги одного типа — например, выделить каждый абзац.
Выбор по атрибуту name: getElementsByName
Возвращает живую NodeList элементов с одинаковым атрибутом name. Чаще всего используется для элементов форм — например, для всех переключателей одной группы:
const options = document.getElementsByName('plan');
options.forEach((radio) => {
radio.addEventListener('change', () => {
console.log('Selected plan:', radio.value);
});
});Подробнее о работе с формами читайте в разделе работа с формами в DOM.
Выбор с помощью CSS-селекторов: querySelector
querySelector возвращает первый элемент, соответствующий переданному CSS-селектору, или null, если совпадений нет. Это наиболее универсальный метод для выбора одного элемента.
const element = document.querySelector('.example');
element.style.backgroundColor = 'lightblue';Поскольку метод принимает полный синтаксис CSS-селекторов, можно точно указать глубоко вложенный элемент: querySelector('nav ul li.active a') находит первую подходящую ссылку без цепочки нескольких вызовов.
Выбор всех совпадений: querySelectorAll
Возвращает статическую NodeList всех элементов, соответствующих селектору. В отличие от getElementsBy..., этот снимок не обновляется при последующих изменениях DOM.
const elements = document.querySelectorAll('.example');
elements.forEach((element, index) => {
element.style.backgroundColor = 'lightgreen';
element.textContent = `Element ${index + 1} highlighted!`;
});NodeList имеет метод forEach, поэтому по ней можно итерировать напрямую. Для использования map/filter сначала преобразуйте её с помощью Array.from(elements).
querySelectorAll возвращает статическую NodeList — она не отразит элементы, добавленные или удалённые после вызова. getElementsByClassName и getElementsByTagName возвращают живые HTMLCollection, которые отслеживают изменения. Выбирайте статическую коллекцию, когда вам нужен стабильный снимок; живую — когда коллекция должна следить за DOM.
Ограничение поиска областью элемента
Все методы querySelector* и getElementsBy* доступны не только на document, но и на отдельных элементах. Вызов метода на элементе ограничивает поиск потомками этого элемента:
const card = document.querySelector('.card');
const title = card.querySelector('.title'); // only inside .cardОграничение области поиска ускоряет запросы и предотвращает случайное совпадение с элементами в других частях страницы.
Проверка элемента: matches
matches не возвращает элемент — он возвращает true/false в зависимости от того, соответствует ли данный элемент CSS-селектору. Метод идеально подходит для обработчиков событий и делегирования событий.
const element = document.getElementById('test');
if (element.matches('.example')) {
element.style.color = 'red';
element.textContent = 'Element matches the selector!';
}Подъём по дереву: closest
closest начинает с самого элемента и поднимается по его предкам, возвращая ближайшего из них, соответствующего селектору (или null). Это самый удобный способ найти элемент-контейнер.
const element = document.getElementById('child');
const parent = element.closest('.outer');
parent.style.border = '2px solid red';matches + closest — основа делегирования событий: добавьте один обработчик к контейнеру, а внутри него используйте event.target.closest('.item'), чтобы определить, какой дочерний элемент был нажат. Подробнее в разделе обработка событий в DOM.
Комбинирование селекторов для точного выбора
CSS-селекторы можно комбинировать, получая нужную точность без лишнего кода:
const element = document.querySelector('.example.special');
element.style.backgroundColor = 'pink';
element.textContent = 'Special element highlighted!';Здесь .example.special соответствует элементу, который имеет оба класса. Можно комбинировать операторы (>, пробел для потомков, +, ~), селекторы атрибутов (input[type="email"]) и псевдоклассы (li:first-child).
Какой метод выбрать?
| Метод | Возвращает | Живой? | Лучше использовать для |
|---|---|---|---|
getElementById | один элемент / null | н/п | одного элемента с известным уникальным ID |
getElementsByClassName | HTMLCollection | живой | всех элементов с классом, отслеживая DOM |
getElementsByTagName | HTMLCollection | живой | всех элементов с тегом |
getElementsByName | NodeList | живой | элементов форм с одинаковым name |
querySelector | первое совпадение / null | н/п | первого элемента по любому CSS-селектору |
querySelectorAll | NodeList | статический | стабильного снимка всех совпадений |
matches | boolean | н/п | проверки соответствия элемента селектору |
closest | ближайший предок / null | н/п | поиска элемента-контейнера |
Практические рекомендации:
- По умолчанию используйте
querySelector/querySelectorAll— единый API с полной мощью CSS. - Используйте
getElementById, когда у вас есть уникальный ID и нужен максимально быстрый поиск. - Прибегайте к живой коллекции (
getElementsBy...) только тогда, когда вам действительно нужно отслеживать изменения DOM; в остальных случаях предпочитайте статическийquerySelectorAll.
Типичные ошибки
- Результат
null.getElementById,querySelectorиclosestвозвращаютnull, когда совпадений нет. Всегда проверяйте результат перед использованием. - Запуск до создания DOM. Если скрипт выполняется в
<head>до разбора элементов, выборки не находят ничего. Размещайте скрипты в конце<body>, используйтеdeferили ждите событияDOMContentLoaded. - Коллекции — не array. У
HTMLCollectionнет методаforEach. УNodeListестьforEach, но нетmap/filter. При сомнениях преобразуйте черезArray.from().
Заключение
Выбор элементов — это отправная точка для любой работы с DOM. В большинстве случаев querySelector и querySelectorAll дают удобный и мощный CSS-ориентированный API; getElementById остаётся самым быстрым вариантом для уникальных ID; а matches и closest обеспечивают чистое делегирование событий. Освоив выбор элементов, переходите к манипуляциям с DOM и перемещению по DOM.
Замечание о производительности: все эти методы достаточно быстры для типичных страниц. Реальная нагрузка возникает при многократном их вызове в плотных циклах — кэшируйте результат выборки в переменной вместо повторных запросов. Статические NodeList из querySelectorAll избавляют от накладных расходов на отслеживание изменений, которые несут живые HTMLCollection.