Реализация атрибутов в Internet Explorer радикально отличается от той, которую предписывает стандарт DOM и которая реализована во всех остальных браузерах. Internet Explorer (здесь и далее, речь идёт о IE версии ниже 8) не различает атрибуты и свойства, что делает работу с атрибутами весьма затруднительной. Более того, это способствует тому, что некоторые начинающие веб-программисты не понимают разницы между атрибутами и свойствами.
Этот материал объясняет назначение атрибутов и свойств и представляет примеры их использования.
Далее обсуждаются различия реализации в Internet Explorer, последствия этих различий и написание кроссбраузерных приложений. Возможно эта статья поможет кому-нибудь не наступить на грабли, о которые уже споткнулось множество программистов.
Атрибуты и свойства в модели DOM
Для каждого тега в XML и HTML может быть указано произвольное количество атрибутов. Атрибут представляет из себя пару строк имя/значение и задается в коде документа: Code (HTML)
Здесь у тега input три атрибута: id, type и value со значениями textField, text и 5 соответственно. Заметим, что в HTML регистр букв в имени атрибута не имеет значения, в отличие от XML/XHTML.
DOM позволяет читать атрибуты из скриптов с помощью методов hasAttribute() и getAttribute(): Code (HTML)
Можно и менять атрибуты, для этого существуют методы setAttribute() и removeAttribute(): Code (HTML)
В наших примерах мы работает с объектом inputTag, который соответствует тегу input документа. У этого объекта есть ряд свойств, некоторые из которых названы так же, как и атрибуты тега: Code (HTML)
Если судить по этому примеру, то атрибут type и свойство type ничем не отличаются. У них всегда одно и то же значение, а результат при изменении атрибута такой же, как и при изменении свойства. Более того, если изменить атрибут, то меняется и свойство: Code (HTML)
Можно изменить и свойство, атрибут тоже автоматически изменится. Это связано с тем, что браузер автоматически синхронизирует значения атрибутов и свойств. И все же они не всегда идентичны: Code (HTML)
Это хорошо показывает разницу атрибута и свойства: атрибут может быть любой строкой, он лишь показывает, что написано в исходном коде документа. Свойства же отображают текущее состояние тега, они не могут содержать недопустимых значений.
Еще более явной становится разница, если посмотреть на атрибут value и свойство value. Code (HTML)
Здесь атрибут и свойство имеют разные значения: атрибут value определяет начальное значение для текстового поля. Текущее же значение хранится в свойстве value и меняется через него же.
Не всегда у атрибута и связанного с ним по смыслу свойства одинаковые названия. Типичным исключением является атрибут class, которому соответствует свойство className. Часто отличается и тип данных, к примеру значение атрибута onclick (как и в принципе всех атрибутов) строкового типа, а у соответствующего свойства onclick значением является функция.-
Реализация атрибутов в Internet Explorer
Разработчики IE упростили модель DOM до предела уравняв атрибуты и свойства. В этом браузере следующие две строки абсолютно эквивалентны: Code (HTML)
При таком подходе немедленно возникает множество осложнений. Первое связано с тем, что регистр букв в имени свойств играет роль, в то время как в имени атрибутов он игнорируется (как минимум в HTML). В Internet Explorer же следующие две строки вдруг приобретают разное значение: Code (HTML)
Эти строки устанавливают два разных свойства объекта. Возникает вопрос - что вернет в этой ситуации inputTag.getAttribute("ABRAKADABRA")? Ответ: либо abcd1, либо abcd2. В Internet Explorer getAttribute() ищет первое свойство с именем, которое соответствует запрошенному атрибуту за вычетом регистра букв. Если таких свойств несколько, то сложно сказать, какое именно он вернет. ›› inputTag.getAttribute("ABRAKADABRA") (проверить)
Следующее осложнение возникает с атрибутами, название которых не идентично названию свойства: Code (HTML)
Эта строчка корректно изменит класс тега во всех браузерах. Лишь в Internet Explorer она установит свойство class, не имеющее никакого значение - нужное свойство называется className. С этой проблемой сталкиваются настолько часто, что она даже заслужила упоминания в MSDN.
Иначе говоря, для изменения класса проще изменить свойство className, это работает одинаково надежно во всех браузерах.
Но на этом проблемы не кончаются. Как уже было сказано, тип атрибутов и свойств не обязательно одинаков. Чаще всего проблемы возникают при установке обработчиков событий: Code (HTML)
После выполнения этого кода в Internet Explorer щелчки на текстовом поле не вызовут никакой реакции. Причина станет ясна, если сравнить значения свойства onclick в Internet Explorer и каком-нибудь другом браузере: Code (HTML)
›› alert(typeof inputTag.onclick) (проверить)
Это покажет, что Internet Explorer записал в свойство onclick строку, в то время как другие браузеры корректно преобразовали значение атрибута в функцию. А при возникновении события Internet Explorer не находит в свойстве onclick функции, которую можно выполнить. Чтобы присвоить обработчик события в Internet Explorer надо написать: Code (HTML)
Стандарт DOM, однако, явно предписывает, что второй параметр метода setAttribute() является строкой. Такой код, опять же, не станет работать ни в одном браузере, корректно реализующем стандарты.
Выводы
Проще всего, конечно, вообще отказаться от использования атрибутов и пользоватьсятолько свойствами. Для большинства приложений этого достаточно, но существуют задачи, где без атрибутов не обойтись (к примеру копирование DOM-дерева с параллельным его изменением). В таких случаях можно выполнять для Internet Explorer другой код, который дает похожий результат (возможно, не идеальный, но лучше, чемвообще никакого результата): Code (JavaScript) document.body.setAttribute("class", "attribute-test"); if (document.body.className == "attribute-test") { // Атрибуты работают корректно (не Internet Explorer или исправленная версия) // Работаем с атрибутами } else { // Использовать атрибуты нельзя (Internet Explorer версии меньше 8) // Альтернативный код только для Internet Explorer }