Відповіді:
Ви завжди повинні використовувати прямий .attribute
форму (але дивіться посилання quirksmode нижче), якщо хочете програмного доступу в JavaScript. Він повинен правильно обробляти різні типи атрибутів (подумати "onload").
Використовуйте getAttribute
/ setAttribute
коли ви бажаєте мати справу з DOM таким, яким він є (наприклад, лише дослівний текст). Різні браузери плутають ці два. Див. Режими Quirks: сумісність атрибутів (in) .
З 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
НЕ визначено, тому вам потрібно отриматиAttribute, щоб отримати значення назад.
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>
Caveat: Це пояснення того, як визначається специфікація 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
s включають властивість, яку називають attributes
. HTMLElement.attributes
є живим NamedNodeMap
Об'єктом, що стосується елементів у DOM. "Live" означає, що коли вузол змінюється в DOM, вони змінюються на стороні JavaScript, і навпаки. Атрибути DOM, в даному випадку, - це відповідні вузли. A Node
має .nodeValue
властивість, яку ви можете змінити. NamedNodeMap
об’єкти мають функцію, яку називають, setNamedItem
де можна змінити весь вузол. Ви також можете безпосередньо отримати доступ до вузла клавішею. Наприклад, ви можете сказати, .attributes["dir"]
що таке саме, як .attributes.getNamedItem('dir');
(Side note, 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-compitation . В основному для того, щоб:
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
ще perfomrant тоді posElem.style = newStyle
?
методи встановлення атрибутів (наприклад, клас) для елемента: 1. el.className = рядок 2. el.setAttribute ('клас', рядок) 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%, але, мабуть, це тому, що "async" підтримується лише в браузерах, які підтримують пряме .attr =
призначення. Отже, немає сенсу намагатися, sestAttribute("async")
тому що якщо браузер не зрозуміє .async=...
- він не зрозуміє атрибут "async".
Будемо сподіватися, що це корисне розуміння мого поточного дослідницького проекту "Un-minify GAPI" . Виправте мене, якщо я помиляюся.
.setAttribute()
на[key] = value
, все почало магічно працювати.