Respuestas:
Siempre debes usar el directo .attribute
forma (pero vea el enlace del modo peculiar a continuación) si desea acceso programático en JavaScript. Debe manejar los diferentes tipos de atributos (piense "onload") correctamente.
Use getAttribute
/ setAttribute
cuando desee tratar con el DOM tal como está (por ejemplo, solo texto literal). Diferentes navegadores confunden a los dos. Ver modos peculiares: compatibilidad de atributo (in) .
Desde Javascript: la guía definitiva , aclara las cosas. Señala que HTMLElement objetos de un documento HTML definen propiedades JS que corresponden a todos los atributos HTML estándar.
Por lo tanto, solo necesita usar setAttribute
para atributos no estándar.
Ejemplo:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
node.frameborder
NO esté definido, por lo que debe obtenerAttribute para recuperar el valor.
frameBorder
directamente, pero tenga en cuenta la capitalización. Alguien pensó que era una buena idea camelCase los equivalentes de JavaScript de los atributos HTML. No he logrado encontrar ninguna especificación para esto, pero la red parece estar de acuerdo en que se trata de 12 casos específicos (al menos para HTML 4). Consulte, por ejemplo, la siguiente publicación: drupal.org/node/1420706#comment-6423420
usemap
atributo no se puede establecer utilizando la notación de puntos al crear el mapa dinámicamente para una imagen. Requiere img.setAttribute('usemap', "#MapName");
¿Su respuesta implica que, usemap
por lo tanto, es "no estándar"?
Ninguna de las respuestas anteriores está completa y la mayoría contiene información errónea.
Hay tres formas de acceder a los atributos de un elemento DOM en JavaScript. Los tres funcionan de manera confiable en los navegadores modernos siempre que comprenda cómo utilizarlos.
element.attributes
Los elementos tienen atributos de propiedad que devuelve un NamedNodeMap de objetos Attr en vivo . Los índices de esta colección pueden ser diferentes entre los navegadores. Por lo tanto, el pedido no está garantizado. NamedNodeMap
tiene métodos para agregar y eliminar atributos ( getNamedItem
y setNamedItem
, respectivamente).
Tenga en cuenta que aunque XML explícitamente distingue entre mayúsculas y minúsculas, la especificación DOM requiere que los nombres de cadena se normalicen , por lo que los nombres pasados no getNamedItem
distinguen entre mayúsculas y minúsculas.
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
Estos métodos existen directamente en el Element
sin necesidad de acceder attributes
y sus métodos, pero realizan las mismas funciones.
Nuevamente, observe que el nombre de la cadena no distingue entre mayúsculas y minúsculas.
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
Se puede acceder a muchos atributos utilizando propiedades convenientes en el objeto DOM. Los atributos que existen dependen del tipo de nodo DOM, no de qué atributos están definidos en el HTML. Las propiedades se definen en algún lugar de la cadena de prototipos del objeto DOM en cuestión. Las propiedades específicas definidas dependerán del tipo de elemento al que esté accediendo. Por ejemplo, className
y id
se definen Element
y existen en todos los nodos DOM que son elementos (es decir, no nodos de texto o comentario). Pero value
es más estrecho. Está definido HTMLInputElement
y puede no existir en otros elementos.
Tenga en cuenta que las propiedades de JavaScript distinguen entre mayúsculas y minúsculas. Aunque la mayoría de las propiedades usarán minúsculas, algunas son camelCase. Así que siempre verifique las especificaciones para estar seguro.
Este "gráfico" captura una parte de la cadena de prototipo para estos objetos DOM. Ni siquiera está cerca de completarse, pero captura la estructura general.
____________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>
Advertencia: esta es una explicación de cómo las especificaciones HTML definen y los navegadores modernos manejan los atributos. No intenté lidiar con las limitaciones de los antiguos navegadores rotos. Si necesita admitir navegadores antiguos, además de esta información, necesitará saber qué está roto en esos navegadores.
Un caso que encontré donde setAttribute
es necesario es al cambiar los atributos ARIA, ya que no hay propiedades correspondientes. Por ejemplo
x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');
No hay x.arialabel
nada ni nada por el estilo, por lo que debe usar setAttribute.
Editar: x ["etiqueta aria"] no funciona . Realmente necesitas 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"
Estas respuestas no abordan realmente la gran confusión entre las propiedades y los atributos . Además, dependiendo del prototipo de Javascript, a veces puedes usar la propiedad de un elemento para acceder a los atributos y otras veces no.
Primero, debe recordar que an HTMLElement
es un objeto Javascript. Como todos los objetos, tienen propiedades. Claro, puede crear una propiedad llamada casi cualquier cosa que desee dentro HTMLElement
, pero no tiene que hacer nada con el DOM (lo que está en la página). La notación de puntos ( .
) es para propiedades . Ahora, hay algunas propiedades especiales . que se asignan a los atributos, y en el momento de la escritura solo hay 4 que están garantizadas (más sobre eso más adelante).
Todos los HTMLElement
s incluyen una propiedad llamada attributes
. HTMLElement.attributes
es un objeto vivo NamedNodeMap
que se relaciona con los elementos en el DOM. "En vivo" significa que cuando el nodo cambia en el DOM, cambian en el lado de JavaScript, y viceversa. Los atributos DOM, en este caso, son los nodos en cuestión. A Node
tiene una .nodeValue
propiedad que puede cambiar. NamedNodeMap
Los objetos tienen una función llamada setNamedItem
donde puede cambiar todo el nodo. También puede acceder directamente al nodo con la tecla. Por ejemplo, puede decir .attributes["dir"]
cuál es el mismo que .attributes.getNamedItem('dir');
(Nota NamedNodeMap
al margen, no distingue entre mayúsculas y minúsculas, por lo que también puede pasar 'DIR'
);
Hay una función similar directamente en HTMLElement
donde puede llamar, setAttribute
que creará automáticamente un nodo si no existe y establecerá el nodeValue
. También hay algunos atributos a los que puede acceder directamente como propiedades a HTMLElement
través de propiedades especiales , como dir
. Aquí hay un mapeo aproximado de cómo se ve:
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 || ''
}
Para que pueda cambiar los dir
atributos de 6 maneras:
// 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';
Puede actualizar todas las propiedades con métodos # 1-5, pero sólo dir
, id
, lang
, y className
con el método # 6.
HTMLElement
tiene esas 4 propiedades especiales. Algunos elementos son clases extendidas o HTMLElement
tienen incluso más propiedades mapeadas. Por ejemplo, HTMLAnchorElement
tiene HTMLAnchorElement.href
, HTMLAnchorElement.rel
, y HTMLAnchorElement.target
. Pero tenga cuidado , si establece esas propiedades en elementos que no tienen esas propiedades especiales (como en a HTMLTableElement
), entonces los atributos no se cambian y son solo propiedades personalizadas normales. Para comprender mejor, aquí hay un ejemplo de su herencia:
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 || ''
}
Ahora la gran advertencia: al igual que todos los objetos Javascript , puede agregar propiedades personalizadas. Pero, esos no cambiarán nada en el DOM. Tu puedes hacer:
const newElement = document.createElement('div');
// THIS WILL NOT CHANGE THE ATTRIBUTE
newElement.display = 'block';
Pero eso es lo mismo que
newElement.myCustomDisplayAttribute = 'block';
Esto significa que no se vinculará la.attributes[attr].nodeValue
adición de una propiedad personalizada .
Actuación
He creado un caso de prueba jsperf para mostrar la diferencia: https://jsperf.com/set-attribute-comparison . Básicamente, en orden:
dir
, id
, className
).element.attributes.ATTRIBUTENAME.nodeValue =
element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
element.attributes.ATTRIBUTENAME = newNode
element.attributes.setNamedItem(ATTRIBUTENAME) = newNode
Conclusión (TL; DR)
Utilizar las asignaciones de propiedades especiales de HTMLElement
: element.dir
, element.id
, element.className
, o element.lang
.
Si está 100% seguro de que el elemento es extendido HTMLElement
con una propiedad especial, use esa asignación especial. (Puedes consultar con if (element instanceof HTMLAnchorElement)
).
Si está 100% seguro de que el atributo ya existe, use element.attributes.ATTRIBUTENAME.nodeValue = newValue
.
Si no, úsalo setAttribute()
.
classList
está 100% garantizado de existir, pero no es una propiedad de cadena, es un DOMTokenList
objeto vivo . Establecer .className
directamente es más rápido que manipular classList
, pero sobrescribiría todo.
.value
, está cambiando el valor interno de HTMLInputElement
, que luego se refleja en los atributos. Tampoco tienen que serlo string
. .valueAsNumber
cambiará value
internamente , y su string
forma aparecerá en el value
atributo. developer.mozilla.org/en-US/docs/Web/HTML/Attributes
"¿Cuándo usar setAttribute vs .attribute = en JavaScript?"
Una regla general es usar .attribute
y verificar si funciona en el navegador.
.. Si funciona en el navegador, ya está listo.
Si no es así, use en .setAttribute(attribute, value)
lugar de .attribute
para ese atributo.
Enjuague y repita para todos los atributos.
Bueno, si eres flojo, simplemente puedes usarlo .setAttribute
. Eso debería funcionar bien en la mayoría de los navegadores. (Aunque los navegadores que admiten .attribute
pueden optimizarlo mejor que .setAttribute(attribute, value)
).
Este parece un caso en el que es mejor usar setAttribute:
Dev.Opera - JavaScript eficiente
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
No funciona en todos los navegadores (funcionó para mí en Firefox)? ¿Es solo por razones de rendimiento lo que setAttribute
se prefiere, evitando las repintado? ¿Es posElem.style.cssText = newStyle
más perfumante entonces posElem.style = newStyle
?
métodos para establecer atributos (por ejemplo, clase) en un elemento: 1. el.className = string 2. el.setAttribute ('class', string) 3. el.attributes.setNamedItem (objeto) 4. el.setAttributeNode (nodo)
Hice una prueba de referencia simple ( aquí )
y parece que setAttributeNode es aproximadamente 3 veces más rápido que usar setAttribute.
así que si el rendimiento es un problema, use "setAttributeNode"
Interesante extracción de la secuencia de comandos API de Google con respecto a esto:
Lo hacen así:
var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";
Observe cómo se usan setAttribute
para "src" y "nonce", pero luego .async = ...
para el atributo "async".
No estoy 100% seguro, pero probablemente se deba a que "async" solo es compatible con los navegadores que admiten la .attr =
asignación directa . Entonces, no tiene sentido tratar desestAttribute("async")
porque si el navegador no comprende .async=...
, no entenderá el atributo "asíncrono".
Con suerte, esa es una idea útil de mi proyecto de investigación en curso "Un-minify GAPI" . Corrígeme si me equivoco.
.setAttribute()
a[key] = value
, todo comenzó a funcionar mágicamente.