DOM, часть 4 из 4. Атрибуты и свойства
13.05.2022
Теги: DOM • Frontend • HTML • JavaScript • Web-разработка • Документ • Теория
HTML-атрибуты
При написании HTML-кода мы можем задавать атрибуты для атрибуты HTML-элементов. Атрибуты могут быть стандартными и нестандартными, причем стандартный атрибут для одного тега может быть нестандартным для другого. Например, атрибут type
является стандартным для элемента <input>
, но не является стандартным для <body>
.
Все атрибуты доступны с помощью следующих методов:
elem.hasAttribute(name)
— проверяет наличие атрибутаelem.getAttribute(name)
— получает значение атрибутаelem.setAttribute(name, value)
— устанавливает значение атрибутаelem.removeAttribute(name)
— удаляет атрибут
Эти методы работают именно с тем, что мы написали в HTML-коде. Имена HTML-атрибутов регистронезависимы, а значения всегда являются строками. Получить все атрибуты элемента можно с помощью свойства elem.attributes
— это коллекция объектов, которая принадлежит ко встроенному классу Attr
со свойствами name
и value
.
<body id="content" something="some value"> <script> // имя атрибута не завистит от регистра if (document.body.hasAttribute('ID')) { alert(document.body.getAttribute('id')); // content } // пример чтения нестандартного атрибута alert(document.body.getAttribute('something')); // some value // добавим еще один атрибут для body document.body.setAttribute('style', 'background:yellow'); // покажем весь список атрибутов body for (let attr of document.body.attributes) { alert(`${attr.name} = ${attr.value}`); } </script> </body>
DOM-свойства
Когда браузер загружает страницу, он «читает» HTML-код и генерирует из него DOM-объекты. Для узлов-элементов большинство стандартных HTML-атрибутов автоматически становятся свойствами DOM-объектов. Например, для тега <body id="page">
у DOM-объекта будет такое свойство body.id="page"
.
DOM-узлы — это обычные объекты JavaScript, мы можем их изменять:
document.body.something = { name: 'some name', value: 'some value' };
document.body.sayTagName = function() { alert(this.tagName); };
Синхронизация атрибутов и свойств
Когда стандартный атрибут изменяется, соответствующее свойство автоматически обновляется. Это работает и в обратную сторону (за некоторыми исключениями).
<input> <script> let input = document.querySelector('input'); // атрибут => свойство input.setAttribute('id', 'email'); alert(input.id); // email (обновлено) // свойство => атрибут input.id = 'phone'; alert(input.getAttribute('id')); // phone (обновлено) </script>
<input> <script> let input = document.querySelector('input'); // атрибут => свойство input.setAttribute('value', 'значение'); alert(input.value); // значение // свойство => атрибут input.value = 'новое значение'; alert(input.getAttribute('value')); // значение (не обновилось!) </script>
В примере выше:
- Изменение атрибута
value
обновило свойство - Но изменение свойства не повлияло на атрибут
Иногда эта «особенность» может пригодиться, потому что действия пользователя могут приводить к изменениям value
, и если после этого мы захотим восстановить «оригинальное» значение из HTML-кода, оно будет в атрибуте.
DOM-свойства типизированы
DOM-свойства не всегда являются строками. Например, свойство input.checked
(для чекбоксов) имеет логический тип.
<input id="input" type="checkbox" checked> <script> alert(input.getAttribute('checked')); // значение атрибута — пустая строка alert(input.checked); // значение свойства — логическое true </script>
Есть и другие примеры. Атрибут style
— строка, но свойство style
является объектом:
<div id="div" style="color:red;font-size:120%">Hello</div> <script> // атрибут style — строка alert(div.getAttribute('style')); // color:red;font-size:120% // свойство style — объект alert(div.style); // [object CSSStyleDeclaration] alert(div.style.color); // red </script>
Хотя большинство свойств, всё же, строки. При этом некоторые из них, хоть и строки, могут отличаться от атрибутов. Например, DOM-свойство href всегда содержит полный URL, даже если атрибут содержит относительный URL или просто #hash
.
<a id="link" href="#hello">Ссылка</a> <script> // атрибут href alert(link.getAttribute('href')); // #hello // свойство href alert(link.href); // полный URL в виде http://site.com/some/path#hello </script>
Если же нужно значение href
или любого другого атрибута в точности, как оно записано в HTML-коде, можно воспользоваться getAttribute
.
Нестандартные атрибуты, dataset
При написании HTML-кода мы используем много стандартных атрибутов. Но что насчёт нестандартных, пользовательских? Они тоже часто нужны — например, для передачи пользовательских данных из HTML-кода в JavaScript, или чтобы «помечать» HTML-элементы для JavaScript.
<!-- пометить div, чтобы показать здесь name --> <div show-info="name"></div> <!-- пометить div, чтобы показать здесь age --> <div show-info="age"></div> <script> // код находит элемент с пометкой и показывает информацию let user = { name: 'Сергей', age: 25 }; for (let div of document.querySelectorAll('[show-info]')) { // вставить соответствующую информацию в поле let field = div.getAttribute('show-info'); div.textContent = user[field]; } </script>
Но с пользовательскими атрибутами могут возникнуть проблемы. Что если мы используем нестандартный атрибут для наших целей, а позже он появится в стандарте и будет выполнять какую-то функцию? Чтобы избежать конфликтов, были придуманы data
-атрибуты, доступ к значениям которых из js-кода возможен через dataset
.
<div id="user" data-name="Сергей" data-age="25"></div> <script> alert(user.dataset.name); // Сергей alert(user.dataset.age); // 25 </script>
className и classList
Изменение класса является одним из наиболее часто используемых действий в скриптах. Атрибут class
в HTML-коде соответствует атрибуту className
элемента.
<body class="main page"> <script> alert(document.body.className); // main page </script> </body>
Если мы присваиваем что-то elem.className
, то это заменяет всю строку с классами. Иногда это то, что нам нужно, но часто мы хотим добавить или удалить один класс. Для этого есть другое свойство — elem.classList
.
<body class="main page"> <script> // добавление css-класса для body document.body.classList.add('article'); alert(document.body.className); // main page article </script> </body>
Так что мы можем работать как со строкой полного класса, используя className
, так и с отдельными классами, используя classList
.
elem.classList.add(class)
— добавить css-классelem.classList.remove(class)
— удалить css-классelem.classList.toggle(class)
— добавить css-класс, если его нет, иначе — удалитьelem.classList.contains(class)
— проверка наличия css-класса, возвращаетtrue
илиfalse
Кроме того, classList
является перебираемым, поэтому можно перечислить все классы при помощи цикла:
<body class="main page"> <script> for (let name of document.body.classList) { alert(name); // main, page } </script> </body>
- DOM, часть 3 из 3. Поиск элементов
- DOM, часть 2 из 3. Изменение документа
- DOM, часть 1 из 3. Навигация по элементам
- Браузерные события, часть 5 из 5. Генерация пользовательских событий
- Браузерные события, часть 4 из 5. Действие браузера по умолчанию
- Браузерные события, часть 3 из 5. Делегирование
- Браузерные события, часть 2 из 5. Погружение и всплытие
Поиск: DOM • Frontend • HTML • JavaScript • Web-разработка • Документ • Теория