316 votes

Quand utiliser setAttribute ou .attribute= en JavaScript ?

Il existe une meilleure pratique concernant l'utilisation setAttribute au lieu du point ( . ) a été développée ?

Par exemple :

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

ou

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

7 votes

Quand je suis passé de .setAttribute() a [key] = value tout a commencé à fonctionner comme par magie.

199voto

olan Points 660

De Javascript : Le Guide Définitif il clarifie les choses. Il note que HTMLElement d'un document HTML définissent les propriétés JS qui correspondent à tous les attributs HTML standard.

Il 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

2 votes

Et de plus, il apparaît après le dernier setAttribute dans votre exemple, node.frameborder n'est PAS défini, vous devez donc utiliser getAttribute pour récupérer la valeur.

8 votes

@Michael correct - si vous utilisez setAttribute pour définir une valeur, vous devez utiliser getAttribute pour la récupérer.

8 votes

Il n'y a rien de mal à mettre frameBorder directement, mais notez la majuscule. Quelqu'un a pensé que c'était une très bonne idée de mettre en majuscules les équivalents JavaScript des attributs HTML. Je n'ai pas réussi à trouver de spécification à ce sujet, mais le net semble s'accorder sur le fait qu'il s'agit de 12 cas spécifiques (pour HTML 4 au moins). Voir par exemple le post suivant : drupal.org/node/1420706#comment-6423420

121voto

ben Points 495

Aucune des réponses précédentes n'est complète et la plupart contiennent des informations erronées.

Il y a trois façons d'accéder aux attributs d'un DOM Élément en JavaScript. Tous trois fonctionnent de manière fiable dans les navigateurs modernes, pour autant que vous compreniez comment les utiliser.

1. element.attributes

Les éléments ont une propriété attributs qui renvoie une NamedNodeMap de Attr objets. Les index de cette collection peuvent être différents selon les navigateurs. L'ordre n'est donc pas garanti. NamedNodeMap possède des méthodes pour ajouter et supprimer des attributs ( getNamedItem y setNamedItem respectivement).

Notez que bien que XML soit explicitement sensible à la casse, la spécification DOM appelle à noms de chaînes à normaliser Ainsi, les noms transmis à getNamedItem sont effectivement insensibles à la casse.

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 le Element sans avoir besoin d'accéder à attributes et ses méthodes mais remplissent les mêmes fonctions.

Encore une fois, notez que les noms de chaînes ne sont pas sensibles à 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. Les propriétés de l'objet DOM, telles que element.id

De nombreux attributs sont accessibles en utilisant des propriétés pratiques sur l'objet DOM. Les propriétés qui existent sur un objet donné dépendent du type de nœud DOM de l'objet, indépendamment des attributs spécifiés dans le HTML. Les propriétés disponibles sont définies quelque part dans la chaîne de prototypes de l'objet DOM en question. Ainsi, les propriétés spécifiques qui sont définies dépendront du type d'élément auquel vous accédez.

Par exemple, className y id sont définis sur Element et existent sur tous les noeuds du DOM qui sont des éléments, mais pas sur les noeuds de texte ou de commentaire. value est plus étroitement défini. Il n'est disponible que sur HTMLInputElement et ses descendants.

Notez que les propriétés JavaScript sont sensibles à la casse. Bien que la plupart des propriétés utilisent des minuscules, certaines sont en camelCase. Vérifiez donc toujours la spécification pour être sûr.

Ce "tableau" capture une partie de la chaîne de prototypes pour ces objets DOM. Il est loin d'être complet, mais il illustre 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 façon dont la spécification HTML définit les attributs et de la façon dont les navigateurs modernes et éternels les gèrent. Il existe certainement d'anciens navigateurs (IE, Netscape, etc.) qui n'ont pas adhéré à la spécification ou qui l'ont même précédée. Si vous devez prendre en charge d'anciens navigateurs (cassés), vous aurez besoin de plus d'informations que celles fournies ici.

77voto

Vous devez toujours utiliser la méthode directe .attribute (mais voir le lien quirksmode ci-dessous) si vous voulez un accès programmé 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 qu'il est (par exemple, le texte littéral uniquement). Les différents navigateurs confondent les deux. Voir Modes de bizarrerie : (in)compatibilité des attributs .

25voto

Antimony Points 13190

J'ai trouvé un cas où setAttribute est nécessaire lorsqu'il s'agit de modifier des attributs ARIA, car il n'existe pas de propriétés correspondantes. Par exemple

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

Il n'y a pas x.arialabel ou quoi que ce soit d'autre, 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"

23voto

ShortFuse Points 562

Ces réponses n'abordent pas vraiment la grande confusion qui existe entre propriétés y attributs . De plus, selon le prototype Javascript, il est parfois possible d'utiliser la propriété d'un élément pour accéder à un attribut, parfois non.

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é portant le nom que vous voulez dans l'objet HTMLElement mais il n'a rien à faire avec le DOM (ce qui se trouve sur la page). La notation par points ( . ) est pour propriétés . Maintenant, il y a certains spéciaux propriétés qui sont mappés à des attributs, et au moment où nous écrivons ces lignes, il n'y en a que 4 qui sont garantis (nous y reviendrons plus tard).

Tous HTMLElement comprennent une propriété appelée attributes . HTMLElement.attributes es un en direct NamedNodeMap Objet qui se rapporte aux éléments dans le DOM. "Live" signifie que lorsque le nœud change dans le DOM, il change du côté JavaScript, et vice versa. Les attributs DOM, dans ce cas, sont les nœuds en question. A Node a un .nodeValue que vous pouvez modifier. NamedNodeMap ont une fonction appelée setNamedItem où vous pouvez modifier 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'); (Note complémentaire, NamedNodeMap n'est pas sensible à la casse, donc vous pouvez également passer la commande 'DIR' ) ;

Il existe une fonction similaire directement dans HTMLElement où vous pouvez simplement appeler setAttribute qui créer automatiquement un nœud s'il n'existe pas et définir le nodeValue . Il existe également un peu de auxquels vous pouvez accéder directement en tant que propriétés dans HTMLElement via propriétés particulières tels que dir . Voici une cartographie approximative de ce à quoi cela 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 || ''

}

Donc vous pouvez changer le dir attributs 6 façons :

  // 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 y className avec la méthode n°6.

Extensions de HTMLElement

HTMLElement possède ces 4 propriétés spéciales. Certains éléments sont des classes étendues de HTMLElement ont des propriétés encore plus cartographiées. Par exemple, HTMLAnchorElement tiene HTMLAnchorElement.href , HTMLAnchorElement.rel y HTMLAnchorElement.target . Mais, attention Si vous définissez ces propriétés sur des éléments qui ne possèdent pas ces propriétés spéciales (par exemple, sur un élément HTMLTableElement ), les attributs ne sont pas modifiés et il s'agit simplement de 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 grand avertissement : Comme tous les objets Javascript vous pouvez ajouter des propriétés personnalisées. Mais, celles-ci ne changeront rien sur le DOM. Vous pouvez le 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 cas de test jsperf pour montrer la différence : https://jsperf.com/set-attribute-comparison . En gros, dans l'ordre :

  1. Les propriétés personnalisées car elles n'affectent pas le DOM et sont pas les attributs .
  2. Les mappages spéciaux fournis par le navigateur ( dir , id , className ).
  3. Si les attributs existent déjà , element.attributes.ATTRIBUTENAME.nodeValue =
  4. setAttribute() ;
  5. Si les 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 une extension 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() .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X