Эти ответы на самом деле не решают большую путаницу между свойствами и атрибутами .Кроме того, в зависимости от прототипа Javascript, иногда вы можете использовать свойство элемента для доступа к атрибутам, а иногда нет.
Во-первых, вы должны помнить, что HTMLElement
является объектом Javascript.Как и все объекты, они имеют свойства.Конечно, вы можете создать свойство под названием почти все, что вы хотите внутри HTMLElement
, но оно не должно иметь ничего общего с DOM (что на странице).Точечная запись (.
) предназначена для свойств .Теперь есть некоторые специальные свойства , которые сопоставляются с атрибутами, и на момент написания этой статьи гарантировано только 4 (подробнее об этом позже).
Все HTMLElement
включаютсвойство под названием attributes
.HTMLElement.attributes
- это live 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
HTMLElement
обладает этими 4 особыми свойствами.Некоторые элементы расширенных классов HTMLElement
имеют еще более сопоставленные свойства.Например, HTMLAnchorElement
имеет HTMLAnchorElement.href
, HTMLAnchorElement.rel
и HTMLAnchorElement.target
.Но, будьте осторожны , если вы устанавливаете эти свойства для элементов, которые не имеют этих специальных свойств (например, для 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. В основном, по порядку:
- Пользовательские свойства, поскольку они не влияют на DOM и не являются атрибутами .
- Специальные отображения, предоставляемые браузером (
dir
, id
, className
). - Если атрибуты уже существуют ,
element.attributes.ATTRIBUTENAME.nodeValue =
- setAttribute ();
- Если атрибуты уже существуют ,
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()
.