В наших прошлых
занятиях мы не раз отмечали, что узлы DOM-дерева – это объекты языка JavaScript. Но раз это
так, значит, мы можем добавлять в них свои собственные свойства. Например,
возьмем объект body:
let body = document.body;
и пропишем в нем
новое свойство myStyle:
body.myStyle = "color: red";
и отобразим его
в консоле:
console.log(body.myStyle);
Видим, что у
нашего объекта добавилось новое свойство. Мы можем даже поступить так:
body.myStyle = {
color: "red",
fontSize: 20
}
console.log(body.myStyle.fontSize);
И теперь, наше
свойство ссылается на объект со стилями. Наконец, никто нам не мешает прописать
и новый метод для объекта body:
body.getFontSize = function() {
return this.myStyle.fontSize;
}
console.log( body.getFontSize() );
Как видите это
все работает, так как DOM-объекты – это обычные объекты JavaScript.
Однако, с
добавлением новых свойств и методов нужно быть осторожными. Если какое-либо
свойство уже существует и мы пытаемся его изменить, то оно либо изменится на
другое или же возникнет ошибка, если свойство неизменяемое. Но как понять:
какие свойства есть у DOM-объекта, а каких нет. Один из вариантов
– просмотреть существующие свойства с помощью вывода объекта в консоль через
метод dir:
Некоторые из
этих свойств могут быть изменены, а другие – нет. Причем, значения этих свойств
присваиваются автоматически браузером при создании DOM-дерева.
Например, у нас имеется такая строчка:
<div id="comm">Сообщения от пользователей</div>
Здесь автоматически
будет создан объект div со свойством id, равным comm. Можем в этом
убедиться, если выведем его в консоль:
let div = document.getElementById("comm");
console.dir( div );
Вообще, всем
стандартным атрибутам автоматически присваиваются соответствующие значения. Но,
что если мы прописываем в теге какой-нибудь нестандартный атрибут, например:
<div id="comm" deflt="значение">Сообщения</div>
Тогда при
попытке его вывести в консоль
console.log( div.deflt );
мы увидим
значение undefined. Это говорит о
том, что оно не создано в явном виде. Но это не значит, что его нет. Для работы
с такими нестандартными свойствами следует пользоваться следующими методами:
-
elem.hasAttribute(name)
– проверяет наличие атрибута;
-
elem.getAttribute(name)
– получает значение атрибута;
-
elem.setAttribute(name,
value) – устанавливает значение атрибута;
-
elem.removeAttribute(name)
– удаляет атрибут.
Например:
console.log( div.getAttribute("deflt") );
div.setAttribute("deflt", "новое значение");
console.log( div.getAttribute("deflt") );
А полный список
указанных атрибутов в HTML-документе, хранится в коллекции attributes:
for(let val of div.attributes)
console.log(val);
Здесь тонким
моментом является то, что все значения нестандартных атрибутов могут быть
только строками: не числами, не объектами, а только строками. Даже если мы
указываем какой-то другой тип данных, он автоматически будет приведет к строке.
Вот это следует иметь в виду.
Стандартные
атрибуты могут принимать другие типы данных. Например, если у нас есть вот
такой checkbox:
<input id="input" type="checkbox" checked> checkbox
то при выводе
типа свойства checked:
let inp = document.getElementById("input");
console.log( typeof inp.checked );
увидим булевый
тип. Хотя большинство стандартных свойств все же являются строками.
Теперь давайте
подробнее посмотрим для чего могут быть использованы нестандартные атрибуты. В
первом случае они могут помочь нам выбрать необходимые узлы DOM-дерева и
прописать им заданные свойства. Например, пусть у нас имеется вот такая
таблица:
<table><tr>
<td cell-red="#CC0000">1</td><td cell-blue="#0000CC">2</td>
<td cell-red="#CC0000">3</td><td cell-blue="#0000CC">4</td>
</tr>
<tr>
<td cell-blue="#0000CC">5</td><td cell-red="#CC0000">6</td>
<td cell-blue="#0000CC">7</td><td cell-red="#CC0000">8</td>
</tr></table>
Для перебора
всех ячеек с атрибутом cell-red можно
воспользоваться таким скриптом:
for(let cell of document.querySelectorAll('[cell-red]')) {
let attr = cell.getAttribute('cell-red');
cell.style.background = attr;
}
Мы здесь с
помощью querySelectorAll выбрали все элементы с атрибутом cell-red и, затем,
присвоили им указанный цвет фона. В ряде случаев это может быть очень удобно.
Во втором случае
мы можем использовать эти атрибуты в таблице стилей, например, так:
<style>
td[cell-red="#CC0000"] {
background: #CC0000;
}
td[cell-red="lightRed"] {
background: #FF9999;
}
</style>
И далее, через JavaScript мы можем
управлять этими стилями так:
let flSkip = false;
for(let cell of document.querySelectorAll('[cell-red]')) {
if(!flSkip) cell.setAttribute('cell-red', 'lightRed');
flSkip = !flSkip;
}
В ряде случаев
это добавляет гибкости и элегантности в управлении элементами HTML-документа.
Но здесь, как
всегда, есть одна тонкость: что если нестандартный атрибут cell-red появится в
будущих версиях языка JavaScript и станет уже
стандартным? Это может привести к непредсказуемому поведению нашей программы в
будущем. Чтобы такого не было создатели языка JavaScript решили, что все
атрибуты, начинающиеся с префикса
data-
будут заведомо
восприниматься как нестандартные. Поэтому, наш скрипт лучше переписать так:
<table><tr>
<td data-cell-red="#CC0000">1</td>
<td data-cell-blue="#0000CC">2</td>
<td data-cell-red="#CC0000">3</td>
<td data-cell-blue="#0000CC">4</td>
</tr>
<tr>
<td data-cell-blue="#0000CC">5</td>
<td data-cell-red="#CC0000">6</td>
<td data-cell-blue="#0000CC">7</td>
<td data-cell-red="#CC0000">8</td>
</tr></table>
Стили будут выглядеть
так:
<style>
td[data-cell-red="#CC0000"] {
background: #CC0000;
}
td[data-cell-red="lightRed"] {
background: #FF9999;
}
</style>
И скрипт примет вид:
let flSkip = false;
for(let cell of document.querySelectorAll('[data-cell-red]')) {
if(!flSkip) cell.setAttribute('data-cell-red', 'lightRed');
flSkip = !flSkip;
}
Мало того, все
эти свойства с префиксом data- становятся доступными через
специальную коллекцию dataset, которая имеется у всех DOM-элементов:
if(!flSkip) cell.dataset.cellRed = 'lightRed';
причем, сам
префикс data- опускается и
оставшееся имя записывается по следующему правилу:
-
если
свойство использует дефисы, то в dataset оно прописывается в верблюжьей
нотации (например, data-cell-red => cellRed);
-
в
остальных случаях просто используется оставшееся имя (например, data-color => color).
Вот так можно
добавлять свои собственные свойства, методы и атрибуты в объекты DOM-дерева.