Réponses:
Vous devez toujours utiliser le .attribute
formulaire 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
/ 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) 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 setAttribute
des attributs non standard.
Exemple:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
node.frameborder
n'est PAS défini, vous devez donc obtenir getAttribute pour récupérer la valeur.
frameBorder
directement, 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
usemap
attribut 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 usemap
c'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.attributes
Les é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. NamedNodeMap
a des méthodes pour ajouter et supprimer des attributs ( getNamedItem
et 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 à getNamedItem
ne 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.setAttribute
Ces méthodes existent directement sur le Element
sans avoir besoin d'accéder à attributes
ses 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.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 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, className
et id
sont définis sur Element
et 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 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. 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 setAttribute
est 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.arialabel
rien 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 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 à 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 HTMLElement
s incluent une propriété appelée attributes
. HTMLElement.attributes
est 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 Node
possède une .nodeValue
propriété que vous pouvez modifier. NamedNodeMap
les objets 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 le même que .attributes.getNamedItem('dir');
(Note latérale, NamedNodeMap
ne respecte pas la casse, vous pouvez donc également passer 'DIR'
);
Il y a une fonction similaire directement dans HTMLElement
laquelle vous pouvez simplement appeler setAttribute
qui 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 HTMLElement
via 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 dir
attributs 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
, lang
et className
avec la méthode # 6.
HTMLElement
a ces 4 propriétés spéciales. Certains éléments sont des classes étendues de HTMLElement
propriétés encore plus mappées. Par exemple, HTMLAnchorElement
a HTMLAnchorElement.href
, HTMLAnchorElement.rel
et 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 = newValue
element.attributes.ATTRIBUTENAME = newNode
element.attributes.setNamedItem(ATTRIBUTENAME) = newNode
Conclusion (TL; DR)
Utilisez les correspondances 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 é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()
.
classList
est garanti à 100%, mais ce n'est pas une propriété de chaîne, c'est un DOMTokenList
objet vivant . La définition .className
directe 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
. .valueAsNumber
changera en value
interne , et sa string
forme apparaîtra dans l' value
attribut. 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 .attribute
puissent 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 = newStyle
fonctionne pas dans tous les navigateurs (a fonctionné pour moi dans Firefox)? Est-ce uniquement pour des raisons de performances qui setAttribute
sont privilégiées, en évitant les repeints? Est-ce posElem.style.cssText = newStyle
plus 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 setAttribute
pour "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.