Атрибуты и свойства элементов в DOM

При построении страницы браузер берёт информацию об элементах из их атрибутов. Но, кроме того, все элементы страницы являются объектами со своими свойствами, которые также учитываются при отображении элементов. DOM-интерфейс позволяет работать и с атрибутами элементов и с их свойствами. При этом необходимо понимать разницу между ними, знать, что и где использовать.

Атрибуты элементов

В HTML-документах теги могут иметь определённые атрибуты с заданными значениями. Атрибуты могут влиять на отображение элемента на странице или изменять его назначение. Поэтому для манипулирования элементами страницы должна быть предоставлена возможность работы с атрибутами HTML-тегов.

DOM-интерфейс представляет набор методов для работы с атрибутами элементов.

element.hasAttribute(атрибут)
Проверяет наличие атрибута.
element.getAttribute(атрибут)
Возвращает строку со значением атрибута.
element.setAttribute(атрибут, значение)
Создаёт атрибут или присваивает ему новое значение.
element.removeAttribute(атрибут)
Удаляет атрибут.

Эти методы работают именно с HTML-атрибутами как они есть в документе. Фактически, они изменяют код страницы. Поэтому для них справедливо:

  • Значения атрибутов - это всегда строки.
  • Имя атрибута можно указывать в любом регистре, так как HTML не предъявляет требований к регистру символов в коде.
<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p><a>Первый</a></p>
</body>
</html>

<script>
  var anch = document.querySelector('a');
  alert(anch.hasAttribute('href')); /* false */
  anch.setAttribute('href', 'home.html');
  alert(anch.getAttribute('href')); /* строка 'home.html' */
  anch.removeAttribute('HREF');
  alert(anch.hasAttribute('href')); /* false, атрибут удалился вне зависимости от регистра */
</script>

Свойства элементов

В DOM каждый элемент является объектом своего класса. При создании модели страницы для каждого элемента браузер создаёт определённые свойства. В них содержится информация о текущем состоянии данного элемента, которую можно изменить. Также, любому элементу можно присвоить совершенно любые свойства, как и для любого объекта в JavaScript.

<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p>Lorem ipsum dolor...</p>
</body>
</html>

<script>
  var par = document.querySelector('p');
  par.firstParagraph = true;
  alert(par.firstParagraph); /* true */
</script>

В отличие от атрибутов:

  • Значение свойства может быть любого типа.
  • Имена свойств регистрозависимы.

Связь свойств с атрибутами

В DOM-интерфейсе понятия HTML-атрибутов и DOM-свойств элементов тесно связаны. При создании модели страницы для каждого элемента создаются одноимённые с атрибутами свойства и присваиваются им те же значения. Однако, это справедливо не для всех атрибутов, что приводит к некоторой путанице, но, чаще, это бывает полезно.

При выводе в окне браузера параметры элемента зависят именно от его свойств. Дальнейшее управление элементами на странице осуществляется изменением этих свойств. Поэтому в основном требуется работать со свойствами элементов, а не с артибутами. Атрибуты, обычно, используются для хранения информации.

Например, поле для ввода текста <input> имеет атрибут value. При построении документа создаётся элемент со свойством value, которое имеет значение, указанное в HTML-коде страницы. Текст для отображения в поле берётся именно из свойства value. Если пользователь вводит свой текст в поле, то свойство автоматически принимает новое текущее значение. При этом код страницы не меняется, поэтому первоначальное значение атрибута остаётся доступным.

<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p><input type="text" value="Текст" autocomplete="off"></p>
</body>
</html>

<script>
  var input = document.querySelector('input');
  alert('Свойство: ' + input.value); /* 'Свойство: Текст' */
  input.value = 'Новый текст'; /* изменили текст в поле */
  alert('Свойство: ' + input.value + '\nАтрибут: ' + input.getAttribute('value')); /* Атрибут не изменился */
</script>

В примере видно, что изменение свойства value не отражается на значении атрибута value. Таким образом, сравнив значения атрибута и свойства, можно понять, был ли изменён текст в поле.

Для элементов создаются свойства не только из указанных в коде атрибутов, а вообще из всех доступных для данного элемента атрибутов, даже если их нет в коде. Сюда включены глобальные атрибуты и атрибуты событий. Такие свойства принимают значения по умолчанию.

<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p><input name="field" value="data"></p>
</body>
</html>

<script>
  var input = document.querySelector('input');
  alert(input.hasAttribute('type')); /* false, атрибута type нет */
  alert('type' in input); /* true, свойство type есть */
  alert(input.type); /* text, значение по умолчанию */
</script>

При построении документа одноимённые атрибуты и свойства не всегда имеют одинаковое значение.

Самый распространённый пример - это атрибут href.

<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p><a href="home.html">Домой</a></p>
</body>
</html>

<script>
  var anch = document.querySelector('a');
  alert(anch.getAttribute('href')); /* home.html */
  alert(anch.href); /* http://web-gain.ru/home.html */
</script>

Свойство href всегда содержит полный (абсолютный) адрес ссылки. Это же касается и свойства src.

Для атрибута булевого типа (hidden, autofocus, checked, disabled, multiple, readonly, required) создаётся одноимённое свойство также булевого типа, то есть со значением true или false. Но в HTML-коде эти атрибуты вообще могут не иметь значений.

Если в HTML-коде будет указан нестандартный для конкретного элемента атрибут, то одноимённое свойство создано не будет.

И это логично, если атрибут не описан в стандарте, значит он не может повлиять на параметры элемента.

<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p><a href="home.html" something="data">Домой</a></p>
</body>
</html>

<script>
  var anch = document.querySelector('a');
  alert(anch.hasAttribute('something')); /* true, атрибут something есть */
  alert('something' in anch); /* false, свойства something нет */
</script>

Проблем с этой особенностью обычно не возникает, так как нестандартные атрибуты почти не используются (с ними страница не проходит валидацию).

Атрибуты data-

dataset

Для передачи информации в HTML введены атрибуты с префиксом data-. С такими атрибутами нужно работать через свойство dataset. Оно содержит список всех data-атрибутов элемента.

<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p><input type="text" data-some-info="something"></p>
</body>
</html>

<script>
  var input = document.querySelector('input');
  alert(input.dataset.someInfo); /* something */
</script>

Атрибут class

className

Свойства с именем class не существует, так как это зарезервированное слово в JavaScript. Атрибуту class соответствует свойство className.

<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p class="first second"></p>
</body>
</html>

<script>
  var par = document.querySelector('p');
  alert(par.className); /* 'first second' */
</script>

Данное свойство удобно использовать, если элементу присвоен только один класс. Но если их несколько, то с этим свойством работать сложнее. Для таких случаев в DOM введено ещё одно свойство для работы с классами - classList.

classList

Свойство classList содержит список (псевдомассив) классов элемента. Для работы с этим массивом можно воспользоваться циклом или встроенными методами:

element.classList.add(класс)
Добавляет класс, если такой класс отсутствует.
element.classList.remove(класс)
Удаляет класс. Если такого класса нет, метод не выдаст ошибку.
element.classList.contains(класс)
Проверяет, имеется ли указанный класс.
element.classList.toggle(класс)
Добавляет класс, если его нет (и возвращает true), или удаляет его, если он уже есть (и возвращает false).
element.classList.replace(старый_класс, новый_класс)
Заменяет указанный класс на новый.
<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p class="first second"></p>
</body>
</html>

<script>
  var par = document.querySelector('p');
  par.classList.remove('second');
  par.classList.add('third');
  alert(par.className); /* 'first third' */
  par.classList.toggle('third');
  alert(par.classList.contains('third')); /* false */
</script>

Атрибут style

style

Свойство style содержит объект-коллекцию всех CSS-свойств элемента. При этом значения имеют только те свойства, которые заданы атрибутом style. Значениями остальных свойств являются пустые строки.

Использование этого свойства очень удобно, так как CSS-свойства элемента, заданные с его помощью, имеют почти самый высокий приоритет (как и атрибут style).

Ещё одним достоинством является то, что с каждым CSS-свойством можно работать отдельно. Свойство style представляет объект, в котором каждому свойству соответствует определённый CSS-стиль.

Кроме того, свойству style можно присвоить стили в виде строки, как это делается с атрибутом style. Для этого используется доступное для записи свойство style.cssText. Однако, необходимо помнить, что присвоение нового значения свойству style.cssText полностью перезаписывает значение атрибута style.

<html>
<head>
  <title>DOM интерфейс</title>
</head>
<body>
  <p><input type="text" value="Текст" style="border: 5px solid red;"></p>
</body>
</html>

<script>
  var input = document.querySelector('input');
  alert(input.style.border); /* 5px solid red */
  alert(input.style.borderWidth); /* 5px, отдельные свойства тоже присвоены */
  input.style.cssText = 'color: red; font-size: 200%'; /* изменили атрибут style */
  alert(input.style.color); /* red */
</script>

Свойство style очень полезно в случаях, когда нужно изменить какое-нибудь CSS-свойство элемента. Но оно не годится для получения значений применённых стилей. Так получается, потому что свойство style получает значения стилей из атрибута style, который используется редко (чаще всего CSS-стили выносятся в отдельный файл).

Чтобы получить значения всех CSS-свойств, применённых к элементу, необходимо воспользоваться методом window.getComputedStyle().

getComputedStyle()

Метод getComputedStyle() объекта window возвращает такой же объект, как и свойство style. Но в нём содержатся значения всех стилей, которые в данный момент применены к элементу (с учётом внешних файлов стилей и тега <style>).

window.getComputedStyle(элемент[, псевдоэлемент])
элемент
Исследуемый элемент (обязательно узел элемент, иначе выдаст ошибку).
псевдоэлемент
Необязательный аргумент. Позволяет указать псевдоэлемент (::after, ::before, ::first-letter, ::first-line), чьи стили необходимо получить.
<html>
<head>
  <title>DOM интерфейс</title>
  <style>
    p {
      font-size: 20px;
    }
    p::first-letter {
      font-size: 30px;
    }
  </style>
</head>
<body>
  <p>Lorem ipsum dolor...</p>
</body>
</html>

<script>
  var par = document.querySelector('p');
  var style = window.getComputedStyle(par);
  var style_pseudo = window.getComputedStyle(par, '::first-letter');
  alert(style.fontSize); /* 20px */
  alert(style_pseudo.fontSize); /* 30px */
</script>

Объект, получаемый данным методом, доступен только для чтения, поэтому с его помощью нельзя поменять стили у элемента. Для замены стилей нужно использовать свойство style элемента.