Wann sollte setAttribute vs .attribute = in JavaScript verwendet werden?

234

Wurde eine bewährte setAttributeMethode für die Verwendung der .Attributnotation dot ( ) entwickelt?

Z.B:

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

oder

myObj.className = "nameOfClass";
myObj.id = "someID";
Francisc
quelle
1
Als ich von .setAttribute()zu wechselte [key] = value, fing alles an, magisch zu funktionieren.
Andrew

Antworten:

73

Sie sollten immer das direkte .attributeFormular verwenden (siehe jedoch den Link zum Quirksmode unten), wenn Sie programmgesteuerten Zugriff in JavaScript wünschen. Es sollte die verschiedenen Arten von Attributen (denken Sie an "Onload") korrekt behandeln.

Verwenden Sie getAttribute/, setAttributewenn Sie das DOM so behandeln möchten, wie es ist (z. B. nur wörtlicher Text). Verschiedene Browser verwechseln die beiden. Siehe Quirks-Modi: Attribut (in) -Kompatibilität .


quelle
127
Diese Antwort ist nicht klar genug ... Ich habe noch nicht das Gefühl, dass ich das verstehe.
temporärer_Benutzername
1
@Aerovistae - stimme dir darin zu. Es wurde eine neue Antwort hinzugefügt, die hoffentlich klarer ist.
Olan
1
Aber wenn Sie die innerHTML des Elements beeinflussen möchten, müssen Sie setAttribute verwenden ...
Michael
3
Du meinst outterHTML * :)
Megawac
4
Ich habe festgestellt, dass a.href die vollständige URL zurückgibt, aber getAttribute ('href') genau das zurückgibt, was in diesem Attribut enthalten ist (<a href = "/ help" ...).
Plastikkaninchen
144

Aus Javascript: The Definitive Guide , es klärt die Dinge. Es wird darauf hingewiesen, dass HTMLElement- Objekte eines HTML-Dokuments JS-Eigenschaften definieren, die allen Standard-HTML-Attributen entsprechen.

Sie müssen sie also nur setAttributefür nicht standardmäßige Attribute verwenden.

Beispiel:

node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
olan
quelle
2
Außerdem wird es angezeigt, nachdem das letzte setAttribute in Ihrem Beispiel node.frameborderNICHT definiert wurde. Sie müssen also getAttribute erhalten, um den Wert zurückzugewinnen.
Michael
5
@Michael richtig - Wenn Sie einen Wert mit setAttribute festlegen, müssen Sie getAttribute verwenden, um ihn abzurufen.
Olan
3
Es ist nichts Falsches daran, frameBorderdirekt einzustellen , aber beachten Sie die Großschreibung. Jemand hielt es für eine gute Idee, die JavaScript-Entsprechungen von HTML-Attributen zu camelCase. Ich habe es nicht geschafft, eine Spezifikation dafür zu finden, aber das Netz scheint zuzustimmen, dass es sich um 12 spezielle Fälle handelt (zumindest für HTML 4). Siehe zum Beispiel den folgenden Beitrag: drupal.org/node/1420706#comment-6423420
aaaaaaaaaaaa
1
Das usemapAttribut kann nicht mit der Punktnotation festgelegt werden, wenn die Karte dynamisch für ein Bild erstellt wird. Erfordert img.setAttribute('usemap', "#MapName");Bedeutet Ihre Antwort, dass dies usemapdaher "nicht standardisiert" ist?
mseifert
1
Das ist meistens falsch. Für einige Attribute sind Eigenschaften definiert, dies ist also nicht der Fall. Es geht wirklich nur darum, wie sie die Spezifikation geschrieben haben. Es hat nichts damit zu tun, dass die Attribute Standard sind oder nicht. Es ist jedoch richtig, dass auf nicht standardmäßige Eigenschaften nur mit getAttribute () zugegriffen werden kann.
Ben
79

Keine der vorherigen Antworten ist vollständig und die meisten enthalten Fehlinformationen.

Es gibt drei Möglichkeiten, auf die Attribute eines DOM- Elements in JavaScript zuzugreifen . Alle drei funktionieren zuverlässig in modernen Browsern, solange Sie wissen, wie man sie verwendet.

1. element.attributes

Elemente haben eine Eigenschaft Attribute , dass die Renditen ein Live - NamedNodeMap von Attr - Objekten. Die Indizes dieser Sammlung können zwischen den Browsern unterschiedlich sein. Die Bestellung ist also nicht garantiert. NamedNodeMapMethoden zum Hinzufügen und Entfernen von Attributen ( getNamedItemund setNamedItemist).

Beachten Sie, dass XML zwar explizit zwischen Groß- und Kleinschreibung unterscheidet, die DOM-Spezifikation jedoch die Normalisierung von Zeichenfolgennamen erfordert , sodass bei Namen, an die übergeben wird, getNamedItemdie Groß- und Kleinschreibung nicht berücksichtigt wird.

Anwendungsbeispiel:

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

Diese Methoden existieren direkt auf dem Elementohne Zugriff attributesund seinen Methoden, führen jedoch dieselben Funktionen aus.

Beachten Sie erneut, dass bei String-Namen die Groß- und Kleinschreibung nicht berücksichtigt wird.

Anwendungsbeispiel:

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. Eigenschaften des DOM-Objekts, z element.id

Auf viele Attribute kann über praktische Eigenschaften des DOM-Objekts zugegriffen werden. Welche Attribute vorhanden sind, hängt vom Typ des DOM-Knotens ab, nicht davon, welche Attribute im HTML definiert sind. Die Eigenschaften werden irgendwo in der Prototypkette des betreffenden DOM-Objekts definiert. Die definierten spezifischen Eigenschaften hängen vom Typ des Elements ab, auf das Sie zugreifen. Zum Beispiel classNameund idsind Elementauf allen DOM-Knoten definiert und vorhanden, die Elemente sind (dh keine Text- oder Kommentarknoten). Ist valueaber enger. Es ist HTMLInputElementfür andere Elemente definiert und möglicherweise nicht vorhanden.

Beachten Sie, dass bei JavaScript-Eigenschaften zwischen Groß- und Kleinschreibung unterschieden wird. Obwohl die meisten Eigenschaften Kleinbuchstaben verwenden, sind einige camelCase. Überprüfen Sie daher immer die Spezifikation, um sicherzugehen.

Dieses "Diagramm" erfasst einen Teil der Prototypkette für diese DOM-Objekte. Es ist noch nicht einmal fast fertig, aber es erfasst die Gesamtstruktur.

                      ____________Node___________
                      |               |         |
                   Element           Text   Comment
                   |     |
           HTMLElement   SVGElement
           |         |
HTMLInputElement   HTMLSpanElement

Anwendungsbeispiel:

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>

Vorsichtsmaßnahme: Dies ist eine Erklärung, wie die HTML-Spezifikation Attribute definiert und moderne Browser damit umgehen. Ich habe nicht versucht, mit den Einschränkungen alter, kaputter Browser umzugehen. Wenn Sie alte Browser unterstützen müssen, müssen Sie zusätzlich zu diesen Informationen wissen, was in diesen Browsern defekt ist.

Ben
quelle
Danke, dass du das geklärt hast. Ich bin gespannt, welche IE-Versionen als "modern" gelten und der HTML-Spezifikation folgen.
jkdev
3
@jkdev IE wird nie modern. Was auch immer es wird, alt zu werden.
Suraj Jain
Vielen Dank für diese detaillierte Antwort. Ich habe viel über DOM und Vererbung gelesen, wie HTMLElement, das von Element geerbt wurde, und so weiter. Ihre Antwort ist absolut sinnvoll.
Suraj Jain
16

Ein Fall, bei dem ich festgestellt habe, dass dies setAttributeerforderlich ist, ist das Ändern von ARIA-Attributen, da keine entsprechenden Eigenschaften vorhanden sind. Beispielsweise

x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');

Da es so x.arialabeletwas nicht gibt, müssen Sie setAttribute verwenden.

Edit: x ["aria-label"] funktioniert nicht . Sie brauchen wirklich 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"
Antimon
quelle
Eigentlich nicht wirklich in Javascript können Sie dies tun x ["Aria-Label"]
Fareed Alnamrouti
@fareednamrouti Das funktioniert nicht. Ich habe es gerade getestet. Die JS-Eigenschaften wirken sich nicht auf die HTML-Attribute aus. Sie brauchen hier wirklich setAttribute.
Antimon
@ Antimon Dies ist seltsam, aber ja, Sie haben 100% Recht, ich werde abstimmen
Fareed Alnamrouti
2
Bist du sicher, dass es kein ariaLabel gibt?
jgmjgm
8

Diese Antworten befassen sich nicht wirklich mit der großen Verwirrung zwischen Eigenschaften und Attributen . Abhängig vom Javascript-Prototyp können Sie manchmal die Eigenschaft eines Elements verwenden, um auf Attribute zuzugreifen, und manchmal nicht.

Zunächst müssen Sie sich daran erinnern, dass an HTMLElementein Javascript-Objekt ist. Wie alle Objekte haben sie Eigenschaften. Natürlich können Sie eine Eigenschaft erstellen, die fast alles enthält, was Sie möchten HTMLElement, aber sie muss nichts mit dem DOM zu tun haben (was auf der Seite steht). Die Punktnotation ( .) steht für Eigenschaften . Jetzt gibt es einige spezielle Eigenschaften , die Attributen zugeordnet sind, und zum Zeitpunkt oder beim Schreiben sind nur 4 garantiert (dazu später mehr).

Alle HTMLElements enthalten eine Eigenschaft namens attributes. HTMLElement.attributesist ein Live- NamedNodeMap Objekt, das sich auf die Elemente im DOM bezieht. "Live" bedeutet, dass sich der Knoten, wenn er sich im DOM ändert, auf der JavaScript-Seite ändert und umgekehrt. DOM-Attribute sind in diesem Fall die fraglichen Knoten. A Nodehat eine .nodeValueEigenschaft, die Sie ändern können. NamedNodeMapObjekte haben eine Funktion namens, setNamedItemmit der Sie den gesamten Knoten ändern können. Sie können auch direkt über den Schlüssel auf den Knoten zugreifen. Zum Beispiel können Sie sagen, .attributes["dir"]was dasselbe ist wie .attributes.getNamedItem('dir');(Randnotiz, NamedNodeMapbei der die Groß- und Kleinschreibung nicht berücksichtigt wird, sodass Sie auch bestehen können 'DIR');

Es gibt eine ähnliche Funktion direkt, in der HTMLElementSie einfach aufrufen können, setAttributewodurch automatisch ein Knoten erstellt wird, wenn er nicht vorhanden ist, und der festgelegt wird nodeValue. Es gibt auch einige Attribute, auf die Sie HTMLElementüber spezielle Eigenschaften direkt als Eigenschaften zugreifen können , z dir. Hier ist eine grobe Abbildung, wie es aussieht:

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 || ''

}

Sie können die dirAttribute also auf 6 Arten ändern :

  // 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';

Sie können alle Eigenschaften mit Methoden # 1-5, aktualisieren , aber nur dir, id, lang, und classNamemit Methode # 6.

Erweiterungen von HTMLElement

HTMLElementhat diese 4 besonderen Eigenschaften. Einige Elemente sind erweiterte Klassen HTMLElementmit noch mehr zugeordneten Eigenschaften. Zum Beispiel HTMLAnchorElementhat HTMLAnchorElement.href, HTMLAnchorElement.relund HTMLAnchorElement.target. Aber Vorsicht , wenn Sie diese Eigenschaften auf Elemente festgelegt , die (wie bei einem nicht die besonderen Eigenschaften haben HTMLTableElement) , dann die Attribute nicht geändert werden und sie sind einfach, normal benutzerdefinierte Eigenschaften. Zum besseren Verständnis hier ein Beispiel für seine Vererbung:

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 || '' 
}

Benutzerdefinierte Eigenschaften

Jetzt die große Warnung: Wie bei allen Javascript-Objekten können Sie benutzerdefinierte Eigenschaften hinzufügen. Diese ändern jedoch nichts am DOM. Du kannst tun:

  const newElement = document.createElement('div');
  // THIS WILL NOT CHANGE THE ATTRIBUTE
  newElement.display = 'block';

Aber das ist das gleiche wie

  newElement.myCustomDisplayAttribute = 'block';

Dies bedeutet, dass das Hinzufügen einer benutzerdefinierten Eigenschaft nicht mit verknüpft wird.attributes[attr].nodeValue .

Performance

Ich habe einen jsperf-Testfall erstellt, um den Unterschied zu zeigen: https://jsperf.com/set-attribute-comparison . Grundsätzlich in der Reihenfolge:

  1. Benutzerdefinierte Eigenschaften, da sie das DOM nicht beeinflussen und keine Attribute sind .
  2. Spezielle Zuordnungen vom Browser zur Verfügung gestellt ( dir, id, className).
  3. Wenn bereits Attribute vorhanden sind ,element.attributes.ATTRIBUTENAME.nodeValue =
  4. setAttribute ();
  5. Wenn bereits Attribute vorhanden sind ,element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
  6. element.attributes.ATTRIBUTENAME = newNode
  7. element.attributes.setNamedItem(ATTRIBUTENAME) = newNode

Schlussfolgerung (TL; DR)

  • Verwenden Sie die spezielle Eigenschaft Zuordnungen von HTMLElement: element.dir, element.id, element.className, oder element.lang.

  • Wenn Sie zu 100% sicher sind, dass das Element eine Erweiterung HTMLElementmit einer speziellen Eigenschaft ist, verwenden Sie diese spezielle Zuordnung. (Sie können mit überprüfen if (element instanceof HTMLAnchorElement)).

  • Wenn Sie zu 100% sicher sind, dass das Attribut bereits vorhanden ist, verwenden Sie element.attributes.ATTRIBUTENAME.nodeValue = newValue.

  • Wenn nicht, verwenden Sie setAttribute().

ShortFuse
quelle
Sie haben diese vier Eigenschaftszuordnungen erwähnt: dir, id, className und lang. Was ist mit classList? Ist classList eine Eigenschaftszuordnung, deren Existenz garantiert ist?
Barzee
classListist zu 100% garantiert, aber es ist keine String-Eigenschaft, sondern ein Live- DOMTokenListObjekt. Das .classNamedirekte Einstellen ist schneller als das Manipulieren classList, aber Sie würden das Ganze überschreiben.
ShortFuse
Wie wäre es mit .value für <input> - und <textarea> -Tags? Was für eine Art sind sie?
Daniel Williams
Die in der Antwort genannten sind das, was W3C "IDL-Attribute widerspiegeln" nennt. Wenn Sie ändern .value, ändern Sie den internen Wert von HTMLInputElement, der sich dann in den Attributen widerspiegelt. Sie müssen es auch nicht sein string. .valueAsNumberändert sich value intern und seine stringForm wird im valueAttribut angezeigt. developer.mozilla.org/en-US/docs/Web/HTML/Attributes
ShortFuse
3

"Wann sollte setAttribute vs .attribute = in JavaScript verwendet werden?"

Eine allgemeine Regel ist, zu verwenden .attributeund zu überprüfen, ob es im Browser funktioniert.

..Wenn es im Browser funktioniert, können Sie loslegen.

..Wenn dies nicht der Fall ist, verwenden Sie .setAttribute(attribute, value)statt .attributefür dieses Attribut.

Spülen-Wiederholen für alle Attribute.

Nun, wenn Sie faul sind, können Sie einfach verwenden .setAttribute. Das sollte in den meisten Browsern gut funktionieren. (Obwohl Browser, die dies unterstützen, .attributees besser optimieren können als .setAttribute(attribute, value).)

Pacerier
quelle
0

Dies scheint ein Fall zu sein, in dem es besser ist, setAttribute zu verwenden:

Dev.Opera - Effizientes 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);
}
tomo7
quelle
2
Vielen Dank, dass Sie diesen tomo7 geteilt haben. Bitte erläutern Sie uns etwas mehr. Funktioniert posElem.style = newStylenicht in allen Browsern (hat bei mir in Firefox funktioniert)? Wird nur aus Leistungsgründen setAttributebevorzugt, um die Neulackierungen zu vermeiden? Ist dann posElem.style.cssText = newStylemehr Perfomrant posElem.style = newStyle?
Noitidart
0

Methoden zum Festlegen von Attributen (z. B. Klasse) für ein Element: 1. el.className = string 2. el.setAttribute ('class', string) 3. el.attributes.setNamedItem (Objekt) 4. el.setAttributeNode (Knoten)

Ich habe einen einfachen Benchmark-Test gemacht ( hier )

und es scheint, dass setAttributeNode ungefähr dreimal schneller ist als die Verwendung von setAttribute.

Wenn also die Leistung ein Problem darstellt, verwenden Sie "setAttributeNode".

Yair Levy
quelle
Ich denke, Sie führen den Test auf Chrom durch. Ich habe auf meinem Mac Chrom, Safari und Firefox verwendet. erwartungsgemäß zeigten 3 von ihnen 3 unterschiedliche Ergebnisse.
Olgun Kaya
0

Interessante Entnahme aus dem Google API-Skript zu diesem Thema :

Sie machen es so:

var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";

Beachten Sie, wie sie setAttributefür "src" und "nonce", dann aber .async = ...für das Attribut "async" verwendet werden.

Ich bin nicht 100% sicher, aber wahrscheinlich liegt das daran, dass "async" nur in Browsern unterstützt wird, die die direkte .attr =Zuweisung unterstützen. Es macht also keinen Sinn, es zu versuchen, sestAttribute("async")denn wenn der Browser es nicht versteht, versteht .async=...er das Attribut "asynchron" nicht.

Hoffentlich ist dies eine hilfreiche Erkenntnis aus meinem laufenden Forschungsprojekt "Un-minify GAPI" . Korrigiere mich, wenn ich falsch liege.

Maxim Mazurok
quelle