Самая большая часть DOM API сосредоточена в свойствах конкретных элементов. В этом уроке мы рассмотрим только самые базовые свойства, чтобы показать, как они работают в принципе.
В повседневной практике программисты постоянно обращаются к документации, чтобы узнать, какие есть свойства и методы у узлов для управления ими.
Так выглядит HTML атрибут="значение"
:
Так выглядит DOM свойство:значение
:
Атрибуты
У каждого тега в HTML есть атрибуты. Некоторые из них общие для всех, другие — специфичные для конкретных тегов:
<a id="aboutPage" href="/pages/about" class="simple">About</a>
В примере выше атрибуты id
и class
можно использовать с любым тегом. Атрибут href
только с некоторыми — например, с тегом <a>
.
Когда браузер загрузил HTML, на его основе строится DOM. Во время обработки, каждый тег становится узлом, а атрибуты – свойствами этого узла. Обычно имена атрибутов и свойств узлов совпадают между собой:
// <a id="aboutPage" href="/pages/about" class="simple">About</a>
const el = document.querySelector('#aboutPage');
el.id; // aboutPage
el.href; // https://ru.hexlet.io/pages/about
Существуют некоторые исключения. Например, атрибут class
соответствует свойству className
. Есть несколько дополнительных способов для удобной работы с классами.
Классов может быть абсолютно любое количество. Они задаются обычной текстовой строкой. Соответственно, если нам нужно изменить этот список, придется работать со строками, что невероятно неудобно.
А вот как это можно сделать с помощью DOM-дерева:
// У тега с таким id класс содержит строку "simple"
const el = document.querySelector('#aboutPage');
el.classList.add('page');
el.classList.remove('simple');
// После всех изменений
el.className; // page
Есть и дополнительные методы:
- Метод
el.classList.contains("class")
проверяет, содержит ли элемент нужный класс, а затем возвращаетtrue
илиfalse
- Метод
el.classList.toggle("class")
проверяет наличие класса. Если класс есть — удаляет его, если нет — добавляет
Именование – это не единственное различие между атрибутами и свойствами. Отличий значительно больше и они не всегда очевидны. Вот лишь некоторые из них:
Атрибут — всегда строка, а свойство — не всегда. Например:
<textarea rows="5"></textarea>
Значение свойства
rows
соответствующего элемента в DOM-дереве будет числом.Атрибуты не чувствительны к регистру:
<a Id="aboutPage" hrEf="/pages/about" CLASS="simple">About</a>
Так писать не стоит, но просто знать об этом факте уже полезно.
Атрибут всегда присутствует в HTML, а значит доступен через
innerHTML
. А вот многие свойства не имеют соответствующих атрибутов. Например, у тега<a>
есть свойствоhash
, но нет такого атрибута.
Как мы увидели выше, атрибут и свойство — это не одно и то же. Поэтому существует набор методов для управления атрибутами:
el.hasAttribute(name)
– проверяет наличие атрибутаel.getAttribute(name)
– получает значение атрибутаel.setAttribute(name, value)
– устанавливает атрибутel.removeAttribute(name)
– удаляет атрибутel.attributes
– выдает список HTML-атрибутов
// Методы работают с атрибутами html
el.getAttribute('class');
Обратите внимание, что они работают именно с атрибутами и их именами, а не свойствами. И позволяют не только их извлекать, но и менять. Возникает закономерный вопрос: поменяется ли атрибут, если поменять свойство и наоборот?
Обычно синхронизация работает так: при изменении атрибута свойство обновляется автоматически.
Но существуют и исключения. Из этих тезисов не следует делать вывод, что нужно стараться работать через атрибуты. Наоборот, старайтесь работать со свойствами DOM-дерева. Атрибуты используйте только для чтения, чтобы получить то состояние, которое было в DOM на момент инициализации — парсинга HTML:
<a id="aboutPage" href="/pages/about" class="simple">About</a>
const el = document.querySelector('#aboutPage');
el.setAttribute('class', 'page');
el.className; // page
el.getAttribute('class'); // page
В отличие от свойств, значение атрибута всегда совпадает с тем, что мы видим в HTML. А вот свойства иногда приводятся в нормализованный вид:
<!-- В этот момент браузер открыт на https://ru.hexlet.io -->
<a id="link-to-courses" href="/courses">Курсы</a>
const el = document.querySelector('#link-to-courses');
el.href; // https://ru.hexlet.io/courses
el.getAttribute('href'); // /courses
Нестандартные атрибуты никогда не превращаются в свойства соответствующих элементов DOM-дерева. Например, если мы добавим атрибут href
в тег p
, то он будет проигнорирован. При этом мы все еще сможем извлечь его через getAttribute
.
Для работы с произвольными свойствами в HTML зарезервирован специальный атрибут data-*
. На месте звездочки может стоять любое слово:
<a href="#" data-toggle="tab">Мои проекты</a>
Такие атрибуты активно используются в JavaScript- плагинах и позволяют не завязываться на классы. В элементах DOM они доступны через специальное свойство dataset
:
console.log(el.dataset.toggle); // => tab
Внутри объекта dataset
имя каждого свойства — это строка после data-
в атрибуте. Если имя содержит дефис, то он удаляется, а следующая за ним буква становится заглавной:
<a href="#" data-nav-toggle="tab">Мои проекты</a>
console.log(el.dataset.navToggle); // => tab
Свойства
В зависимости от типа элемента, меняется и набор свойств, кроме тех, что достались в наследство от Node и Element.
Чтобы узнать список этих свойств, можно обращаться к спецификации. Они описаны в специальном формате, который несложно понять:
// HTMLLinkElement – просто название интерфейса
// HTMLElement – родительский тип, от которого наследуются свойства и методы
// attribute – обозначение конкретного атрибута, его типа и имени
interface HTMLLinkElement : HTMLElement {
// Последнее слово в каждой строке — это имя свойства в объекте
attribute USVString href;
attribute DOMString? crossOrigin;
attribute DOMString rel;
attribute RequestDestination as; // (default "")
readonly attribute DOMTokenList relList;
attribute DOMString media;
attribute DOMString nonce;
attribute DOMString integrity;
attribute DOMString hreflang;
attribute DOMString type;
}
Как и в случае с навигацией по DOM-дереву, не нужно запоминать все особенности поведения атрибутов и свойств. Как правило, понимание приходит на практике во время экспериментов методом проб и ошибок.
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.