Мастер-классы по Javascript Екатеринбург Ростов-на-Дону Москва Узнать больше...
Содержание (скрыть) Содержание (показать)

Атрибуты и пользовательские свойства

  1. Свойства
  2. Атрибуты
  3. Синхронизация свойств и атрибутов
    1. id
    2. href
    3. value
    4. class/className
    5. «Особенности» старых IE
  4. Итого

У DOM-узлов бывают не только свойства, но и атрибуты.

Между ними есть кое-что общее, поэтому иногда их путают. Но на самом деле, атрибуты и свойства — совершенно разные вещи.

Свойства

Узел DOM - это объект. Как и любой объект JavaScript, он может содержать пользовательские свойства и методы.

Например, создадим в document.body новое свойство и запишем в него объект:

document.body.myData = { 
  name: 'Петр',
  familyName: 'Петрович'
};

alert(document.body.myData.name); // Петр

Можно добавить и новую функцию:

document.body.sayHi = function() { 
  alert(this.nodeName);
}
 
document.body.sayHi(); // BODY, выполнилась с правильным this

Такие свойства и методы видны только в JavaScript и никак не влияют на отображение соответствующего тега.

Эти свойства можно даже перечислить с помощью for..in (свойства будут все, и встроенные тоже):

document.body.custom = 5;

var list = [];
for (var key in document.body) {
  list.push(key);
}

alert( list.join('\n') );

Пользовательские DOM-свойства:

  • Могут иметь любое значение.
  • Названия свойств чувствительны к регистру.
  • Работают за счет того, что DOM-узлы являются объектами JavaScript

Атрибуты

Узлы DOM, с другой стороны, являются HTML-элементами, у которых есть атрибуты.
Доступ к атрибутам осуществляется при помощи стандартных методов:

  • elem.hasAttribute(name) - проверяет наличие атрибута
  • elem.getAttribute(name) - получает значение атрибута
  • elem.setAttribute(name, value) - устанавливает атрибут
  • elem.removeAttribute(name) - удаляет атрибут

Атрибуты неправильно работают в IE<8 и в IE8 в режиме совместимости:

  • Существуют только методы getAttribute и setAttribute.
  • Фактически, они изменяют DOM-свойства, а не атрибуты.
  • Атрибуты и свойства в IE<8 объединены. Иногда это приводит к странным результатам, но способы работы с атрибутами, о которых мы здесь говорим, работают правильно.

В отличие от свойств, атрибуты:

  • Могут быть только строками.
  • Их имя нечувствительно к регистру(т.к. это HTML)
  • Они отражены в HTML, включая свойство innerHTML (за исключением старых IE)
  • Все атрибуты элемента можно получить с помощью свойства attributes, которое содержит псевдо-массив объектов типа Attr.

Например, рассмотрим этот HTML-код:

<body>
  <div about="Elephant" class="smiling"></div>
</body>

Пример ниже устанавливает атрибуты и демонстрирует их особенности.

<body>
  <div about="Elephant" class="smiling"></div>

  <script>
    var div = document.body.children[0];
    alert( div.getAttribute('ABOUT') ); // (1)
    
    div.setAttribute('Test', 123);   // (2)
    alert( document.body.innerHTML );   // (3)

    var attrs = div.attributes;  // (4)
    for (var i=0; i<attrs.length; i++) {
      alert(attrs[i].name + " = " + attrs[i].value); 
    }
  </script>
</body>

При запуске кода выше, обратите внимание:

  1. getAttribute('ABOUT') использует имя атрибута в верхнем регистре, но это не имеет значения, т.к имена нечувствительны к регистру.
  2. Вы можете записать в атрибут строку или другое значение, которые будет превращено в строку. Объект, например, будет автоматически сконвертирован, но у IE с этим проблемы, поэтому, придерживайтесь примитивов.
  3. В innerHTML появился новый атрибут "test".
  4. Коллекция attributes содержит все атрибуты в виде объектов класса Attr со свойствами name и value.

Синхронизация свойств и атрибутов

Каждый тип узлов DOM имеет свои стандартные свойства.

Например, свойства тега 'A' описаны в спецификации DOM: HTMLAnchorElement.

Например, у него есть свойство "href". Кроме того, он имеет "id" и другие свойства, общие для всех элементов, которые описаны в спецификации в HTMLElement.

Стандартные свойства DOM синхронизируются с атрибутами.

id

Например, браузер синхронизирует атрибут "id" со свойством id. Изменим одно - поменяется и другое:

<script>
  document.body.setAttribute('id','la-la-la');
  alert(document.body.id); // la-la-la
</script>

href

Синхронизация не гарантирует одинакового значения. Для примера, посмотрим что произойдет с атрибутом "href" при изменении свойства:

<a href="#"></a>
<script>
  var a  = document.body.children[0];

*!*
  a.href = '/';
*/!*

  alert( 'атрибут:' + a.getAttribute('href') ); // '/'
  alert( 'свойство:' + a.href );  // *!*полный URL*/!* (в старых IE '/')

</script>

Это происходит потому, что атрибут может быть любым, а свойство href, в соответствии со спецификацией W3C, должно быть полной ссылкой.

Есть и другие свойства-атрибуты, которые не копируются в точности. Например, таково свойство input.checked:

<input type="checkbox" checked>

<script>
  var input  = document.body.children[0];

  alert( input.checked ); // true <-- может быть только true/false

  alert( input.getAttribute('checked') ); // пустая строка
</script>

value

А еще есть встроенные свойства, которые синхронизируются в одну сторону.

Например, input.value синхронизируется только из атрибута в свойство:

<body>
  <input type="text" value="markup">
  <script>
    var input = document.body.children[0];

    input.setAttribute('value', 'new');

    alert( input.value ); // 'new', input.value изменено
  </script>
</body>

Но атрибут не синхронизируется из свойства:

<body>
  <input type="text" value="markup">
  <script>
    var input = document.body.children[0];

    input.value = 'new';

    alert(input.getAttribute('value')); // 'markup', не изменилось!
  </script>
</body>

В результате атрибут value хранит оригинальное (исходное) значение даже после того, как пользователь заполнил поле и свойство изменилось. Текущее же значение хранится в свойстве value.

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

class/className

Исключение: атрибут "class" соответствует свойству className.

Так как слово "class" является зарезервированным словом в Javascript, то атрибуту "class" соответствует свойство className.

<body>
  <script>
    document.body.setAttribute('class', 'big red bloom');

    alert( document.body.className );  // ^^^
  </script>
</body>

Приведенный пример не работает в IE<9, т.к. в старых IE свойства и атрибуты перемешаны.

В реальной жизни рекомендуется всегда использовать свойство, если оно существует. В данном случае лучше работать с document.body.className и забыть про атрибут.

Итак:

  • Стандартные свойства синхронизируются с атрибутами.
  • .. Но при этом свойство (href) не всегда равно атрибуту.
  • .. Некоторые свойства (value) меняются независимо, т.к. синхронизация односторонняя.
  • Атрибуту class соответствует свойство className.

  1. Получите div в переменную.
  2. Получите значение атрибута "data-widget-name" в переменную.
  3. Выведите его.

Документ:

<body>

  <div data-widget-name="menu">Выберите жанр</div>  

  <script>/* ... */</script>
</body>

Исходный код: tutorial/browser/dom/custom_attribute.html.

Решение
Решение
  1. Для начала, нам нужно получить div. Здесь нет комментариев, так что сработает document.body.children[0] даже для старых IE.

    var div = document.body.children[0];
    

  2. Пользовательский атрибут не попадает в свойства DOM-объекта, поэтому используем
    метод getAttribute().

    <body>
    
      <div data-widget-name="menu">Выберите жанр</div>
    
      <script>
        var div = document.body.children[0];
     
        var widgetName = div.getAttribute('data-widget-name');
     
        alert( widgetName );  // "menu"
      </script>
    </body>
    

«Особенности» старых IE

Для полноты картины ознакомимся с проблемами версий IE<9.

  1. Во-первых, версии IE<9 синхронизируют все свойства и атрибуты, а не только стандартные:

    document.body.setAttribute('my', 123);
    
    alert( document.body.my );  // 123 в IE<9
    

    При этом даже тип данных не меняется. Атрибут не становится строкой, как ему положено.

  2. Во-вторых, в IE8 это исправлено, но в IE<8 (или в IE8 в режиме совместимости с IE7) нет отдельной работы со свойствами и атрибутами. Это одно и то же.

    Но это же разные вещи. Поэтому возникают забавные казусы.

    Например, названия свойств регистрозависимы, а названия атрибутов - нет. Что будет если два свойства имеют одинаковое имя в разном регистре? Как поведет себя соответствующий атрибут?

    document.body.abba = 1; // задаем свойство 
    document.body.ABBA = 5; // задаем свойство, теперь уже прописными буквами
    
    // запрашиваем атрибут в *!*смешаном*/!* регистре
    alert( document.body.getAttribute('AbBa') ); // что должен вернуть браузер?
    

    Браузер выходит из ситуации, возвращая первое назначенное свойство(abba). Также, в IE<9 существует второй параметр для getAttribute, который делает его чувствительным к регистру. Подробнее тут:MSDN getAttribute.

  3. Также есть еще одно следствие смешения свойств с атрибутами в старых IE: изменение атрибута "class" в IE<9 не меняет класс.
    Эта проблема нас никогда не коснется, если мы работаем со свойством className.

Для того, чтобы избежать проблем с IE, используйте атрибуты правильно.

Другими словами, всегда старайтесь использовать свойства, а атрибуты - только там, где это действительно нужно.

А действительно нужны атрибуты лишь в трёх случаях:

  1. Когда нужно получить пользовательский HTML-атрибут, потому что он не синхронизирован со свойством.
  2. Когда нужно получить «оригинальное значение» стандартного HTML-атрибута, например, <INPUT value="...">. Но в IE<8 это не cработает, т.к. там атрибуты смешаны со свойствами, и значение атрибута и свойства будет одинаковое.
  3. Когда нужно получить список всех атрибутов, включая пользовательские. Для этого используется коллекция attributes.

Итого

Таблица сравнений для атрибутов и свойств:

Свойства Атрибуты
Любое значение Строка
Названия регистрозависимы Не чувствительны к регистру
Не видны в innerHTML Видны в innerHTML
Стандартные свойства и атрибуты синхронизируются, некоторые - в одну сторону. Пользовательские - не синхронизируются.
В IE<8 и IE8 в режиме совместимости, свойства и атрибуты смешаны воедино.

Если вы хотите использовать собственные атрибуты в HTML, то помните, что атрибуты с именем, начинающимся на data- валидны в HTML5.

Современные браузеры поддерживают особый доступ к таким атрибутам через DOM: Свойство dataSet для data-* атрибутов.

В реальной жизни, в 98% случаев используются свойства DOM.

Оставшиеся 2% это:

  1. Когда нужно получить пользовательский HTML-атрибут, потому что он не синхронизирован со свойством..
  2. Когда нужно получить именно значение атрибута, потому что в свойстве уже не совсем то (href для ссылки) или оно изменилось (value у INPUT).

Комментарии

  1. Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
  2. Если ваш комментарий касается задачи -- откройте её в отдельном окне и напишите там.
  3. Комментарии без смысла, с рекламой или не о статье вообще - удаляются.
Наверх

Содержание

Реклама

Нашли опечатку?

Нашли опечатку на сайте? Что-то кажется странным?
Выделите соответствующий текст и нажмите Ctrl+Enter!

Последние Комментарии

Помоги другим!

Помоги другим узнать о хорошей статье!