web-dev-qa-db-fra.com

Quand utiliser setAttribute vs .attribute = en JavaScript?

Une pratique exemplaire autour de setAttribute à la place de la notation attributaire point (.) a-t-elle été développée?

Par exemple.:

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

ou

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

Vous devez toujours utiliser le formulaire direct .attribute (mais consultez le lien quirksmode ci-dessous) si vous souhaitez un accès par programmation en JavaScript. Il devrait gérer correctement les différents types d'attributs (pensez "onload").

Utilisez getAttribute/setAttribute lorsque vous souhaitez traiter le DOM tel quel (par exemple, texte littéral uniquement). Différents navigateurs confondent les deux. Voir Modes Quirks: compatibilité (in) attribut .

66
user166390

De Javascript: Le guide définitif , cela clarifie les choses. Il note que les objets HTMLElement d'un document HTML définissent des propriétés JS correspondant à tous les attributs HTML standard.

Il vous suffit donc d’utiliser setAttribute pour les attributs non standard.

Exemple:

node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
127
olan

Aucune des réponses précédentes n'est complète et la plupart contiennent de la désinformation.

Il existe trois manières d'accéder aux attributs d'un DOM Element ​​en JavaScript. Tous les trois fonctionnent de manière fiable dans les navigateurs modernes tant que vous comprenez comment les utiliser.

1. element.attributes

Les éléments ont une propriété attributs qui renvoie un objet NamedNodeMap direct Attr . Les index de cette collection peuvent être différents parmi les navigateurs. Donc, la commande n'est pas garantie. NamedNodeMap a des méthodes pour ajouter et supprimer des attributs (getNamedItem et setNamedItem, respectivement).

Notez que même si XML est explicitement sensible à la casse, la spécification DOM appelle les noms de chaîne à normaliser , de sorte que les noms transmis à getNamedItem ne font réellement pas la différence entre les majuscules et les minuscules.

Exemple d'utilisation:

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

Ces méthodes existent directement sur Element sans avoir besoin d'accéder à attributes et à ses méthodes, mais exécutent les mêmes fonctions.

Encore une fois, notez que le nom de la chaîne ne respecte pas la casse.

Exemple d'utilisation:

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. Propriétés sur l'objet DOM, telles que element.id

De nombreux attributs sont accessibles à l’aide de propriétés pratiques sur l’objet DOM. Les attributs existants dépendent du type du nœud DOM et non des attributs définis dans le code HTML. Les propriétés sont définies quelque part dans la chaîne de prototypes d'objet DOM en question. Les propriétés spécifiques définies dépendront du type d'élément auquel vous accédez. Par exemple, className et id sont définis sur Element et existent sur tous les nœuds DOM qui sont des éléments (c.-à-d. Pas des nœuds de texte ou de commentaire). Mais value est plus étroit. Il est défini sur HTMLInputElement et peut ne pas exister sur d'autres éléments.

Notez que les propriétés JavaScript sont sensibles à la casse. Bien que la plupart des propriétés utilisent des minuscules, certaines sont camelCase. Il faut donc toujours vérifier les spécifications pour en être sûr.

Ce "graphique" capture une partie de la chaîne de prototypes pour ces objets DOM. Ce n'est même pas proche de terminer, mais il capture la structure globale.

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

Exemple d'utilisation:

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>

Avertissement: il s'agit d'une explication de la définition des spécifications HTML et de la gestion des attributs par les navigateurs modernes. Je n'ai pas essayé de gérer les limitations d'anciens navigateurs brisés. Si vous devez prendre en charge les anciens navigateurs, en plus de ces informations, vous devez savoir ce qui ne fonctionne pas dans ces navigateurs.

67
Ben

Un cas que j'ai trouvé où setAttribute est nécessaire est lors du changement d'attributs ARIA, car il n'y a pas de propriétés correspondantes. Par exemple

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

Il n'y a pas de x.arialabel ou quoi que ce soit du genre, vous devez donc utiliser setAttribute.

Edit: x ["aria-label"] ne fonctionne pas. Vous avez vraiment besoin de 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"
14
Antimony

Ces réponses ne traitent pas vraiment de la grande confusion entre les attributs et . En outre, selon le prototype Javascript, vous pouvez parfois utiliser la propriété d'un élément pour accéder à un attribut, et parfois vous ne pouvez pas.

Tout d'abord, vous devez vous rappeler qu'un HTMLElement est un objet Javascript. Comme tous les objets, ils ont des propriétés. Bien sûr, vous pouvez créer une propriété appelée presque tout ce que vous voulez dans HTMLElement, mais elle n’a rien à faire avec le DOM (contenu de la page). La notation par points (.) concerne les propriétés . Maintenant, il y a quelques propriétés spéciales qui sont mappées sur des attributs, et à ce moment-là ou en écrivant, il n'y en a que 4 qui sont garanties (plus sur cela plus tard).

Tous les HTMLElements incluent une propriété appelée attributes. HTMLElement.attributes est un objet en direct NamedNodeMap qui se rapporte aux éléments du DOM. "Live" signifie que lorsque le nœud change dans le DOM, il change du côté JavaScript, et inversement. Les attributs DOM, dans ce cas, sont les nœuds en question. Une Node a une propriété .nodeValue que vous pouvez modifier. Les objets NamedNodeMap ont une fonction appelée setNamedItem où vous pouvez changer le nœud entier. Vous pouvez également accéder directement au nœud par la clé. Par exemple, vous pouvez dire .attributes["dir"] qui est identique à .attributes.getNamedItem('dir'); (la note latérale, NamedNodeMap ne respecte pas la casse, donc vous pouvez également passer 'DIR');

Il y a une fonction similaire directement dans HTMLElement où vous pouvez simplement appeler setAttribute qui créera automatiquement un noeud s'il ne le fait pas. existe et définit la nodeValue. Il existe également des attributs auxquels vous pouvez accéder directement en tant que propriétés dans HTMLElement via des propriétés spéciales , tel que dir. Voici un aperçu de ce à quoi il ressemble:

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

}

Vous pouvez donc modifier les attributs dir de 6 manières:

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

Vous pouvez mettre à jour toutes les propriétés avec les méthodes # 1-5, mais seulement dir, id, lang et className avec la méthode # 6.

Extensions de HTMLElement

HTMLElement a ces 4 propriétés spéciales. Certains éléments sont des classes étendues de HTMLElement ont encore plus de propriétés mappées. Par exemple, HTMLAnchorElement a HTMLAnchorElement.href, HTMLAnchorElement.rel et HTMLAnchorElement.target. Mais méfiez-vous , si vous définissez ces propriétés sur des éléments qui ne possèdent pas ces propriétés spéciales (comme sur un HTMLTableElement), les attributs ne sont pas modifiés et ils le sont. juste, propriétés personnalisées normales. Pour mieux comprendre, voici un exemple de son héritage:

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

Propriétés personnalisées

Maintenant le gros avertissement: Comme tous les objets Javascript , vous pouvez ajouter des propriétés personnalisées. Mais, cela ne changera rien sur le DOM. Tu peux faire:

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

Mais c'est la même chose que

  newElement.myCustomDisplayAttribute = 'block';

Cela signifie que l'ajout d'une propriété personnalisée ne sera pas lié à .attributes[attr].nodeValue.

Performance

J'ai construit un scénario de test jsperf pour montrer la différence: https://jsperf.com/set-attribute-comparison . Fondamentalement, dans l'ordre:

  1. Les propriétés personnalisées car elles n'affectent pas le DOM et sont pas des attributs .
  2. Mappages spéciaux fournis par le navigateur (dir, id, className).
  3. Si des attributs existent déjà , element.attributes.ATTRIBUTENAME.nodeValue =
  4. setAttribute ();
  5. Si des attributs existent déjà , element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
  6. element.attributes.ATTRIBUTENAME = newNode
  7. element.attributes.setNamedItem(ATTRIBUTENAME) = newNode

Conclusion (TL; DR)

  • Utilisez les mappages de propriétés spéciales de HTMLElement: element.dir, element.id, element.className ou element.lang.

  • Si vous êtes sûr à 100% que l'élément est un élément étendu HTMLElement avec une propriété spéciale, utilisez ce mappage spécial. (Vous pouvez vérifier avec if (element instanceof HTMLAnchorElement)).

  • Si vous êtes sûr à 100% que l'attribut existe déjà, utilisez element.attributes.ATTRIBUTENAME.nodeValue = newValue.

  • Sinon, utilisez setAttribute().

2
ShortFuse

"Quand utiliser setAttribute vs .attribute = en JavaScript?"

Une règle générale consiste à utiliser .attribute et à vérifier si cela fonctionne sur le navigateur.

..Si cela fonctionne sur le navigateur, vous êtes prêt à partir.

..Si ce n'est pas le cas, utilisez .setAttribute(attribute, value) au lieu de .attribute pour cet attribut .

Rinçage-répéter pour tous les attributs.

Eh bien, si vous êtes paresseux, vous pouvez simplement utiliser .setAttribute. Cela devrait fonctionner correctement sur la plupart des navigateurs. (Bien que les navigateurs prenant en charge .attribute puissent l’optimiser mieux que .setAttribute(attribute, value).)

2
Pacerier

méthodes de définition des attributs (par exemple, classe) sur un élément: 1. el.className = chaîne 2. el.setAttribute ('classe', chaîne) 3. el.attributes.setNamedItem (objet) 4. el.setAttributeNode (noeud)

J'ai fait un test de référence simple ( ici )

et il semble que setAttributeNode soit environ 3 fois plus rapide que l’utilisation de setAttribute.

donc si les performances sont un problème - utilisez "setAttributeNode"

0
Yair Levy

Cela ressemble à un cas où il est préférable d'utiliser setAttribute:

Dev.Opera - JavaScript efficace

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);
}
0
tomo7