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/ setAttributecuando 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 setAttributepara atributos no estándar.
Ejemplo:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
node.frameborderNO esté definido, por lo que debe obtenerAttribute para recuperar el valor.
frameBorderdirectamente, 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
usemapatributo 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, usemappor 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.attributesLos 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. NamedNodeMaptiene métodos para agregar y eliminar atributos ( getNamedItemy 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 getNamedItemdistinguen 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.setAttributeEstos métodos existen directamente en el Elementsin necesidad de acceder attributesy 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.idSe 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, classNamey idse definen Elementy existen en todos los nodos DOM que son elementos (es decir, no nodos de texto o comentario). Pero valuees más estrecho. Está definido HTMLInputElementy 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 setAttributees 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 HTMLElementes 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 HTMLElements incluyen una propiedad llamada attributes. HTMLElement.attributeses 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 Nodetiene una .nodeValuepropiedad que puede cambiar. NamedNodeMapLos objetos tienen una función llamada setNamedItemdonde 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 NamedNodeMapal margen, no distingue entre mayúsculas y minúsculas, por lo que también puede pasar 'DIR');
Hay una función similar directamente en HTMLElementdonde puede llamar, setAttributeque 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 HTMLElementtravé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 diratributos 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 classNamecon el método # 6.
HTMLElementtiene esas 4 propiedades especiales. Algunos elementos son clases extendidas o HTMLElementtienen incluso más propiedades mapeadas. Por ejemplo, HTMLAnchorElementtiene 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 = newValueelement.attributes.ATTRIBUTENAME = newNode element.attributes.setNamedItem(ATTRIBUTENAME) = newNodeConclusió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 HTMLElementcon 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().
classListestá 100% garantizado de existir, pero no es una propiedad de cadena, es un DOMTokenListobjeto vivo . Establecer .classNamedirectamente 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. .valueAsNumbercambiará value internamente , y su stringforma aparecerá en el valueatributo. developer.mozilla.org/en-US/docs/Web/HTML/Attributes
"¿Cuándo usar setAttribute vs .attribute = en JavaScript?"
Una regla general es usar .attributey 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 .attributepara 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 .attributepueden 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 = newStyleNo funciona en todos los navegadores (funcionó para mí en Firefox)? ¿Es solo por razones de rendimiento lo que setAttributese prefiere, evitando las repintado? ¿Es posElem.style.cssText = newStylemá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 setAttributepara "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.