Réponses:
Vous devez toujours utiliser le .attributeformulaire direct (mais voir le lien quirksmode ci-dessous) si vous voulez un accès programmatique en JavaScript. Il doit gérer correctement les différents types d'attributs (pensez "onload").
Utilisez getAttribute/ setAttributelorsque vous souhaitez traiter le DOM tel quel (par exemple, texte littéral uniquement). Différents navigateurs confondent les deux. Voir Modes Quirks: compatibilité (in) des attributs .
De Javascript: The Definitive Guide , il clarifie les choses. Il note que les objets HTMLElement d'un document HTML définissent des propriétés JS qui correspondent à tous les attributs HTML standard.
Il vous suffit donc d'utiliser setAttributedes attributs non standard.
Exemple:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
node.framebordern'est PAS défini, vous devez donc obtenir getAttribute pour récupérer la valeur.
frameBorderdirectement, mais notez la capitalisation. Quelqu'un a pensé que c'était une bonne idée de camelCase les équivalents JavaScript des attributs HTML. Je n'ai pas réussi à trouver de spécification pour cela, mais le net semble être d'accord 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
usemapattribut ne peut pas être défini à l'aide de la notation par points lors de la création dynamique de la carte pour une image. Cela nécessite img.setAttribute('usemap', "#MapName");Votre réponse implique-t-elle que usemapc'est donc "non standard"?
Aucune des réponses précédentes n'est complète et la plupart contiennent des informations erronées.
Il existe trois façons d'accéder aux attributs d'un élément DOM en JavaScript. Les trois fonctionnent de manière fiable dans les navigateurs modernes tant que vous comprenez comment les utiliser.
element.attributesLes éléments ont des attributs de propriété qui retournent un NamedNodeMap en direct d' objets Attr . Les index de cette collection peuvent être différents selon les navigateurs. Ainsi, la commande n'est pas garantie. NamedNodeMapa des méthodes pour ajouter et supprimer des attributs ( getNamedItemet setNamedItem, respectivement).
Notez que bien que XML soit explicitement sensible à la casse, la spécification DOM appelle à la normalisation des noms de chaîne , de sorte que les noms passés à getNamedItemne respectent pas la casse.
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.setAttributeCes méthodes existent directement sur le Elementsans avoir besoin d'accéder à attributesses méthodes mais remplissent les mêmes fonctions.
Encore une fois, notez que le nom de chaîne n'est pas sensible à la casse.
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.idDe 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 HTML. Les propriétés sont définies quelque part dans la chaîne prototype de l'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, classNameet idsont définis sur Elementet existent sur tous les nœuds DOM qui sont des éléments (c'est-à-dire pas des nœuds de texte ou de commentaire). Mais valueest plus étroit. Il est défini sur HTMLInputElementet 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. Vérifiez donc toujours les spécifications pour en être sûr.
Ce "graphique" capture une partie de la chaîne de prototype pour ces objets DOM. Ce n'est même pas près d'être terminé, mais il capture la structure globale.
____________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>
Mise en garde: il s'agit d'une explication de la façon dont la spécification HTML définit et les navigateurs modernes gèrent les attributs. Je n'ai pas tenté de faire face aux limitations des anciens navigateurs brisés. Si vous devez prendre en charge d'anciens navigateurs, en plus de ces informations, vous devrez savoir ce qui est cassé dans ces navigateurs.
J'ai trouvé un cas où il setAttributeest nécessaire de modifier les 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 x.arialabelrien ou quelque chose comme ça, 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"
Ces réponses ne traitent pas vraiment de la grande confusion entre les propriétés et les attributs . En outre, selon le prototype Javascript, vous pouvez parfois utiliser la propriété d'un élément pour accéder à des attributs et parfois vous ne pouvez pas.
Tout d'abord, vous devez vous rappeler que an HTMLElementest 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 à l'intérieur HTMLElement, mais cela n'a rien à voir avec le DOM (ce qui est sur la page). La notation par points ( .) est pour les propriétés . Maintenant, il y a des propriétés spéciales qui sont mappées aux attributs, et au moment de l'écriture, il n'y en a que 4 qui sont garantis (plus à ce sujet plus tard).
Tous les HTMLElements incluent une propriété appelée attributes. HTMLElement.attributesest un objet vivant 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 vice versa. Les attributs DOM, dans ce cas, sont les nœuds en question. A Nodepossède une .nodeValuepropriété que vous pouvez modifier. NamedNodeMaples objets ont une fonction appelée setNamedItemoù 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 le même que .attributes.getNamedItem('dir');(Note latérale, NamedNodeMapne respecte pas la casse, vous pouvez donc également passer 'DIR');
Il y a une fonction similaire directement dans HTMLElementlaquelle vous pouvez simplement appeler setAttributequi créera automatiquement un nœud s'il n'existe pas et définira le nodeValue. Il existe également certains attributs auxquels vous pouvez accéder directement en tant que propriétés HTMLElementvia des propriétés spéciales , telles que dir. Voici une cartographie approximative 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 dirattributs de 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 des méthodes # 1-5, mais seulement dir, id, langet classNameavec la méthode # 6.
HTMLElementa ces 4 propriétés spéciales. Certains éléments sont des classes étendues de HTMLElementpropriétés encore plus mappées. Par exemple, HTMLAnchorElementa HTMLAnchorElement.href, HTMLAnchorElement.relet HTMLAnchorElement.target. Mais attention , si vous définissez ces propriétés sur des éléments qui n'ont pas ces propriétés spéciales (comme sur a HTMLTableElement), les attributs ne sont pas modifiés et ce sont juste des 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 || ''
}
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 cas de test jsperf pour montrer la différence: https://jsperf.com/set-attribute-comparison . Fondamentalement, dans l'ordre:
dir, id, className).element.attributes.ATTRIBUTENAME.nodeValue = element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValueelement.attributes.ATTRIBUTENAME = newNode element.attributes.setNamedItem(ATTRIBUTENAME) = newNodeConclusion (TL; DR)
Utilisez les correspondances de propriétés spéciales de HTMLElement: element.dir, element.id, element.classNameou element.lang.
Si vous êtes sûr à 100% que l'élément est un étendu HTMLElementavec 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().
classListest garanti à 100%, mais ce n'est pas une propriété de chaîne, c'est un DOMTokenListobjet vivant . La définition .classNamedirecte est plus rapide que la manipulation classList, mais vous écraseriez le tout.
.value, vous modifiez la valeur interne de la HTMLInputElement, qui se reflète ensuite sur les attributs. Ils ne doivent pas non plus l'être string. .valueAsNumberchangera en value interne , et sa stringforme apparaîtra dans l' valueattribut. developer.mozilla.org/en-US/docs/Web/HTML/Attributes
"Quand utiliser setAttribute vs .attribute = en JavaScript?"
Une règle générale consiste à utiliser .attribute et de 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)plutôt que.attribute pour cet attribut.
Rincer-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 qui le prennent en charge .attributepuissent l'optimiser mieux que .setAttribute(attribute, value).)
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);
}
posElem.style = newStylefonctionne pas dans tous les navigateurs (a fonctionné pour moi dans Firefox)? Est-ce uniquement pour des raisons de performances qui setAttributesont privilégiées, en évitant les repeints? Est-ce posElem.style.cssText = newStyleplus perfomant alors posElem.style = newStyle?
méthodes pour définir des attributs (par exemple classe) sur un élément: 1. el.className = string 2. el.setAttribute ('class', string) 3. el.attributes.setNamedItem (object) 4. el.setAttributeNode (node)
J'ai fait un test de référence simple ( ici )
et il semble que setAttributeNode soit environ 3 fois plus rapide que setAttribute.
donc si les performances sont un problème - utilisez "setAttributeNode"
Plats à emporter intéressants à partir du script Google API concernant ceci:
Ils le font comme ceci:
var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";
Remarquez comment ils utilisent setAttributepour "src" et "nonce", mais ensuite .async = ...pour l'attribut "async".
Je ne suis pas sûr à 100%, mais c'est probablement parce que "async" n'est pris en charge que sur les navigateurs qui prennent en charge l' .attr =attribution directe . Donc, cela n'a aucun sens d'essayer sestAttribute("async")parce que si le navigateur ne comprend pas.async=... - il ne comprendra pas l'attribut "async".
J'espère que c'est un aperçu utile de mon projet de recherche "Un-minify GAPI" en cours . Corrige moi si je me trompe.
.setAttribute()à[key] = value, tout a commencé comme par magie.