Когда использовать setAttribute vs .attribute = в JavaScript? - PullRequest
203 голосов
/ 13 октября 2010

Разработан ли передовой опыт использования setAttribute вместо точечной (.) записи атрибутов?

Например:

myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");

или

myObj.className = "nameOfClass";
myObj.id = "someID";

Ответы [ 8 ]

123 голосов
/ 10 января 2014

С Javascript: полное руководство , оно проясняет ситуацию. Он отмечает, что HTMLElement объекты документа HTML определяют свойства JS, которые соответствуют всем стандартным атрибутам HTML.

Так что вам нужно использовать setAttribute только для нестандартных атрибутов.

Пример:

node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
68 голосов
/ 12 апреля 2016

Ни один из предыдущих ответов не является полным и большинство из них содержат дезинформацию.

Существует три способа доступа к атрибутам DOM Элемент в JavaScript. Все три надежно работают в современных браузерах, если вы понимаете, как их использовать.

1. 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>

2. 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>

3. Свойства объекта DOM, такие как 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 определяет и современные браузеры обрабатывают атрибуты. Я не пытался бороться с ограничениями древних, сломанных браузеров. Если вам требуется поддержка старых браузеров, в дополнение к этой информации вам необходимо знать, что в этих браузерах не работает.

66 голосов
/ 13 октября 2010

Вы всегда должны использовать прямую форму .attribute (но смотрите ссылку на причудливый режим ниже), если вам нужен программный доступ в JavaScript.Он должен правильно обрабатывать различные типы атрибутов (подумайте «onload»).

Используйте getAttribute / setAttribute, когда вы хотите работать с DOM как есть (например, только с буквальным текстом).Различные браузеры путают их.См. Причудливые режимы: атрибут (в) совместимости .

13 голосов
/ 05 января 2015

Один случай, который я обнаружил, где необходимо 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"
2 голосов
/ 14 апреля 2019

Эти ответы на самом деле не решают большую путаницу между свойствами и атрибутами .Кроме того, в зависимости от прототипа 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. В основном, по порядку:

  1. Пользовательские свойства, поскольку они не влияют на DOM и не являются атрибутами .
  2. Специальные отображения, предоставляемые браузером (dir, id, className).
  3. Если атрибуты уже существуют , element.attributes.ATTRIBUTENAME.nodeValue =
  4. setAttribute ();
  5. Если атрибуты уже существуют , element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
  6. element.attributes.ATTRIBUTENAME = newNode
  7. 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().

2 голосов
/ 14 апреля 2017

"Когда использовать setAttribute vs .attribute = в JavaScript?"

Общее правило - использовать .attribute и проверять, работает ли оно в браузере.

.. Если он работает в браузере, все готово.

.. Если это не так, используйте .setAttribute(attribute, value) вместо .attribute для этого атрибута .

Полоскание-повтор для всех атрибутов.

Ну, если вам лень, вы можете просто использовать .setAttribute. Это должно работать нормально на большинстве браузеров. (Хотя браузеры, поддерживающие .attribute, могут оптимизировать его лучше, чем .setAttribute(attribute, value).)

0 голосов
/ 10 мая 2017

методы для установки атрибутов (например, класса) для элемента: 1. el.className = строка 2. el.setAttribute ('class', string) 3. el.attributes.setNamedItem (объект) 4. el.setAttributeNode (узел)

Я сделал простой тест ( здесь )

и кажется, что setAttributeNode примерно в 3 раза быстрее, чем setAttribute.

, поэтому, если производительность является проблемой - используйте "setAttributeNode"

0 голосов
/ 11 декабря 2014

Это похоже на один случай, когда лучше использовать 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);
}
...