Ответы:
Вы всегда должны использовать прямую .attribute
форму (но смотрите ссылку на причудливый режим ниже), если вам нужен программный доступ в JavaScript. Он должен правильно обрабатывать различные типы атрибутов (подумайте «onload»).
Используйте getAttribute
/, setAttribute
когда вы хотите иметь дело с DOM как есть (например, только текст). Различные браузеры путают их. См. Причудливые режимы: атрибут (в) совместимости .
От Javascript: Полное руководство , оно проясняет вещи. Он отмечает, что объекты HTMLElement документа HTML определяют свойства JS, которые соответствуют всем стандартным атрибутам HTML.
Так что вам нужно использовать только setAttribute
нестандартные атрибуты.
Пример:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
node.frameborder
НЕ определен, поэтому вы должны получить getAttribute, чтобы получить значение обратно.
frameBorder
напрямую, но обратите внимание на заглавные буквы. Кто-то подумал, что было бы неплохо, если бы CamelCase соответствовал JavaScript-атрибутам HTML. Мне не удалось найти никакой спецификации для этого, но сеть, похоже, согласна с тем, что речь идет о 12 конкретных случаях (по крайней мере, для HTML 4). Смотрите, например, следующий пост: drupal.org/node/1420706#comment-6423420
usemap
Атрибут не может быть установлен с помощью точечной нотации при создании карты динамически для изображения. Это требует, img.setAttribute('usemap', "#MapName");
подразумевает ли ваш ответ, что usemap
поэтому является "нестандартным"?
Ни один из предыдущих ответов не является полным и большинство содержит дезинформацию.
Есть три способа доступа атрибуты DOM элемента в JavaScript. Все три надежно работают в современных браузерах, если вы понимаете, как их использовать.
element.attributes
Элементы имеют свойство атрибутов , который возвращает живой NamedNodeMap из Attr объектов. Индексы этой коллекции могут отличаться в разных браузерах. Итак, заказ не гарантирован. NamedNodeMap
есть методы для добавления и удаления атрибутов ( getNamedItem
и setNamedItem
, соответственно).
Обратите внимание, что хотя XML явно чувствителен к регистру, спецификация DOM требует нормализации строковых имен , поэтому передаваемые имена getNamedItem
фактически нечувствительны к регистру.
var div = document.getElementsByTagName('div')[0];
//you can look up specific attributes
var classAttr = div.attributes.getNamedItem('CLASS');
document.write('attributes.getNamedItem() Name: ' + classAttr.name + ' Value: ' + classAttr.value + '<br>');
//you can enumerate all defined attributes
for(var i = 0; i < div.attributes.length; i++) {
var attr = div.attributes[i];
document.write('attributes[] Name: ' + attr.name + ' Value: ' + attr.value + '<br>');
}
//create custom attribute
var customAttr = document.createAttribute('customTest');
customAttr.value = '567';
div.attributes.setNamedItem(customAttr);
//retreive custom attribute
customAttr = div.attributes.getNamedItem('customTest');
document.write('attributes.getNamedItem() Name: ' + customAttr.name + ' Value: ' + customAttr.value + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
element.getAttribute
&element.setAttribute
Эти методы существуют напрямую, Element
без необходимости доступа attributes
и их методов, но выполняют те же функции.
Опять же, обратите внимание, что имя строки нечувствительно к регистру.
var div = document.getElementsByTagName('div')[0];
//get specific attributes
document.write('Name: class Value: ' + div.getAttribute('class') + '<br>');
document.write('Name: ID Value: ' + div.getAttribute('ID') + '<br>');
document.write('Name: DATA-TEST Value: ' + div.getAttribute('DATA-TEST') + '<br>');
document.write('Name: nonStandard Value: ' + div.getAttribute('nonStandard') + '<br>');
//create custom attribute
div.setAttribute('customTest', '567');
//retreive custom attribute
document.write('Name: customTest Value: ' + div.getAttribute('customTest') + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
element.id
Многие атрибуты могут быть доступны с помощью удобных свойств объекта DOM. Какие атрибуты существуют, зависит от типа узла DOM, а не от того, какие атрибуты определены в HTML. Свойства определены где-то в цепочке прототипов рассматриваемого объекта DOM. Определенные свойства будут зависеть от типа элемента, к которому вы обращаетесь. Например, className
и id
определены Element
и существуют на всех узлах DOM, которые являются элементами (т. Е. Не узлами текста или комментариев). Но value
это более узко. Он определен HTMLInputElement
и может не существовать в других элементах.
Обратите внимание, что свойства JavaScript чувствительны к регистру. Хотя большинство свойств будут использовать строчные буквы, некоторые из них являются camelCase. Так что всегда проверяйте спецификацию, чтобы быть уверенным.
Эта «диаграмма» захватывает часть цепочки прототипов для этих объектов DOM. Это даже не близко к завершению, но он отражает общую структуру.
____________Node___________
| | |
Element Text Comment
| |
HTMLElement SVGElement
| |
HTMLInputElement HTMLSpanElement
var div = document.getElementsByTagName('div')[0];
//get specific attributes
document.write('Name: class Value: ' + div.className + '<br>');
document.write('Name: id Value: ' + div.id + '<br>');
document.write('Name: ID Value: ' + div.ID + '<br>'); //undefined
document.write('Name: data-test Value: ' + div.dataset.test + '<br>'); //.dataset is a special case
document.write('Name: nonStandard Value: ' + div.nonStandard + '<br>'); //undefined
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
Предостережение: это объяснение того, как спецификация HTML определяет и современные браузеры обрабатывают атрибуты. Я не пытался бороться с ограничениями древних, сломанных браузеров. Если вам необходимо поддерживать старые браузеры, в дополнение к этой информации вам необходимо знать, что в этих браузерах не работает.
Один случай, который я нашел там, где setAttribute
это необходимо, - это изменение атрибутов ARIA, поскольку соответствующих свойств нет. Например
x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');
Там нет x.arialabel
или что-то подобное, поэтому вы должны использовать setAttribute.
Редактировать: x ["aria-label"] не работает . Вам действительно нужно setAttribute.
x.getAttribute('aria-label')
null
x["aria-label"] = "Test"
"Test"
x.getAttribute('aria-label')
null
x.setAttribute('aria-label', 'Test2')
undefined
x["aria-label"]
"Test"
x.getAttribute('aria-label')
"Test2"
Эти ответы на самом деле не решают большую путаницу между свойствами и атрибутами . Кроме того, в зависимости от прототипа Javascript, иногда вы можете использовать свойство элемента для доступа к атрибутам, а иногда нет.
Во-первых, вы должны помнить, что HTMLElement
это объект Javascript. Как и все объекты, они имеют свойства. Конечно, вы можете создать свойство, называемое почти всем, что вы хотите внутри HTMLElement
, но оно не должно иметь ничего общего с DOM (что на странице). Точечная запись ( .
) предназначена для свойств . Теперь есть некоторые специальные свойства , которые сопоставляются с атрибутами, и на момент написания этой статьи гарантируется только 4 (подробнее об этом позже).
Все HTMLElement
включают свойство называется attributes
. HTMLElement.attributes
является живым NamedNodeMap
объектом, который относится к элементам в DOM. «Живой» означает, что когда узел изменяется в DOM, он изменяется на стороне JavaScript, и наоборот. Атрибутами DOM в данном случае являются рассматриваемые узлы. А Node
имеет .nodeValue
свойство, которое вы можете изменить. NamedNodeMap
Объекты имеют функцию, которая называется, setNamedItem
где вы можете изменить весь узел. Вы также можете напрямую получить доступ к узлу с помощью ключа. Например, вы можете сказать, .attributes["dir"]
что то же самое, что .attributes.getNamedItem('dir');
(примечание, NamedNodeMap
без учета регистра, так что вы также можете пройти 'DIR'
);
Прямо HTMLElement
там есть похожая функция, в которой вы можете просто вызвать, setAttribute
которая автоматически создаст узел, если он не существует, и установит nodeValue
. Есть также некоторые атрибуты, к которым вы можете обращаться напрямую как к свойствам HTMLElement
через специальные свойства , такие как dir
. Вот примерное отображение того, как это выглядит:
HTMLElement {
attributes: {
setNamedItem: function(attr, newAttr) {
this[attr] = newAttr;
},
getNamedItem: function(attr) {
return this[attr];
},
myAttribute1: {
nodeName: 'myAttribute1',
nodeValue: 'myNodeValue1'
},
myAttribute2: {
nodeName: 'myAttribute2',
nodeValue: 'myNodeValue2'
},
}
setAttribute: function(attr, value) {
let item = this.attributes.getNamedItem(attr);
if (!item) {
item = document.createAttribute(attr);
this.attributes.setNamedItem(attr, item);
}
item.nodeValue = value;
},
getAttribute: function(attr) {
return this.attributes[attr] && this.attributes[attr].nodeValue;
},
dir: // Special map to attributes.dir.nodeValue || ''
id: // Special map to attributes.id.nodeValue || ''
className: // Special map to attributes.class.nodeValue || ''
lang: // Special map to attributes.lang.nodeValue || ''
}
Таким образом, вы можете изменить dir
атрибуты 6 способов:
// 1. Replace the node with setNamedItem
const newAttribute = document.createAttribute('dir');
newAttribute.nodeValue = 'rtl';
element.attributes.setNamedItem(newAttribute);
// 2. Replace the node by property name;
const newAttribute2 = document.createAttribute('dir');
newAttribute2.nodeValue = 'rtl';
element.attributes['dir'] = newAttribute2;
// OR
element.attributes.dir = newAttribute2;
// 3. Access node with getNamedItem and update nodeValue
// Attribute must already exist!!!
element.attributes.getNamedItem('dir').nodeValue = 'rtl';
// 4. Access node by property update nodeValue
// Attribute must already exist!!!
element.attributes['dir'].nodeValue = 'rtl';
// OR
element.attributes.dir.nodeValue = 'rtl';
// 5. use setAttribute()
element.setAttribute('dir', 'rtl');
// 6. use the UNIQUELY SPECIAL dir property
element["dir"] = 'rtl';
element.dir = 'rtl';
Вы можете обновить все свойства с методами # 1-5, но только dir
, id
, lang
и className
с методом # 6.
HTMLElement
имеет эти 4 специальных свойства. Некоторые элементы являются расширенными классами и HTMLElement
имеют еще более сопоставленные свойства. Например, HTMLAnchorElement
есть HTMLAnchorElement.href
, HTMLAnchorElement.rel
и HTMLAnchorElement.target
. Но будьте осторожны , если вы установите эти свойства для элементов, которые не имеют этих специальных свойств (например, для a HTMLTableElement
), тогда атрибуты не изменятся, и они будут обычными обычными свойствами. Чтобы лучше понять, вот пример его наследования:
HTMLAnchorElement extends HTMLElement {
// inherits all of HTMLElement
href: // Special map to attributes.href.nodeValue || ''
target: // Special map to attributes.target.nodeValue || ''
rel: // Special map to attributes.ref.nodeValue || ''
}
Теперь большое предупреждение: как и все объекты Javascript , вы можете добавлять собственные свойства. Но это ничего не изменит на DOM. Ты можешь сделать:
const newElement = document.createElement('div');
// THIS WILL NOT CHANGE THE ATTRIBUTE
newElement.display = 'block';
Но это так же, как
newElement.myCustomDisplayAttribute = 'block';
Это означает, что добавление пользовательского свойства не будет связано с.attributes[attr].nodeValue
.
Производительность
Я создал тестовый пример jsperf, чтобы показать разницу: https://jsperf.com/set-attribute-comparison . В основном, по порядку:
dir
, id
, className
).element.attributes.ATTRIBUTENAME.nodeValue =
element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
element.attributes.ATTRIBUTENAME = newNode
element.attributes.setNamedItem(ATTRIBUTENAME) = newNode
Заключение (TL; DR)
Используйте специальные отображения свойств из HTMLElement
: element.dir
, element.id
, element.className
, или element.lang
.
Если вы на 100% уверены, что элемент является расширенным HTMLElement
со специальным свойством, используйте это специальное отображение. (Вы можете проверить с if (element instanceof HTMLAnchorElement)
).
Если вы на 100% уверены, что атрибут уже существует, используйте element.attributes.ATTRIBUTENAME.nodeValue = newValue
.
Если нет, используйте setAttribute()
.
classList
на 100% гарантированно существует, но это не строковое свойство, это живой DOMTokenList
объект. Установка .className
напрямую быстрее, чем манипулирование classList
, но вы перезаписали бы все это.
.value
, вы меняете внутреннее значение HTMLInputElement
, которое затем отражается на атрибутах. Они также не должны быть string
. .valueAsNumber
изменится value
внутри , и его string
форма появится в value
атрибуте. developer.mozilla.org/en-US/docs/Web/HTML/Attributes
"Когда использовать setAttribute vs .attribute = в JavaScript?"
Общее правило - использовать .attribute
и проверять, работает ли оно в браузере.
..Если это работает в браузере, вы можете идти.
..Если он не используется .setAttribute(attribute, value)
вместо того , чтобы .attribute
для этого атрибута.
Промыть-повторить для всех атрибутов.
Ну, если вы ленивы, вы можете просто использовать .setAttribute
. Это должно нормально работать в большинстве браузеров. (Хотя браузеры, которые поддерживают, .attribute
могут оптимизировать его лучше, чем .setAttribute(attribute, value)
.)
Это похоже на один случай, когда лучше использовать setAttribute:
Dev.Opera - эффективный JavaScript
var posElem = document.getElementById('animation');
var newStyle = 'background: ' + newBack + ';' +
'color: ' + newColor + ';' +
'border: ' + newBorder + ';';
if(typeof(posElem.style.cssText) != 'undefined') {
posElem.style.cssText = newStyle;
} else {
posElem.setAttribute('style', newStyle);
}
posElem.style = newStyle
работает во всех браузерах (у меня работало в Firefox)? Это просто из соображений производительности, что setAttribute
предпочтительнее, избегая перекрашивания? Является ли posElem.style.cssText = newStyle
более духовным, чем posElem.style = newStyle
?
методы для установки атрибутов (например, класса) для элемента: 1. el.className = строка 2. el.setAttribute ('class', строка) 3. el.attributes.setNamedItem (объект) 4. el.setAttributeNode (узел)
Я сделал простой тест ( здесь )
и кажется, что setAttributeNode примерно в 3 раза быстрее, чем использование setAttribute.
поэтому, если производительность является проблемой - используйте "setAttributeNode"
Интересный вывод из скрипта Google API по этому поводу:
Они делают это так:
var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";
Обратите внимание, как они используются setAttribute
для "src" и "nonce", но затем .async = ...
для атрибута "async".
Я не уверен на 100%, но, вероятно, это потому, что «асинхронность» поддерживается только в браузерах, которые поддерживают прямое .attr =
назначение. Таким образом, нет смысла пытаться это сделать, sestAttribute("async")
потому что если браузер не понимает .async=...
- он не поймет атрибут «асинхронный».
Надеюсь, что это полезное понимание моего продолжающегося исследовательского проекта "Un-minify GAPI" . Поправьте меня если я ошибаюсь.
.setAttribute()
на[key] = value
, все волшебным образом начало работать.