Respostas:
Você deve sempre usar o direto .attribute
formulário (mas consulte o link quirksmode abaixo) se desejar acesso programático em JavaScript. Ele deve lidar com os diferentes tipos de atributos (pense em "onload") corretamente.
Use getAttribute
/ setAttribute
quando desejar lidar com o DOM como ele é (por exemplo, apenas texto literal). Navegadores diferentes confundem os dois. Consulte Modos Quirks: compatibilidade de atributos (in) .
Do Javascript: O Guia Definitivo , esclarece as coisas. Ele observa que HTMLElement objetos de um documento HTML definem propriedades JS que correspondem a todos os atributos HTML padrão.
Portanto, você só precisa usar setAttribute
atributos não padrão.
Exemplo:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
node.frameborder
NÃO está definido, portanto você deve getAttribute para recuperar o valor.
frameBorder
diretamente, mas observe a capitalização. Alguém pensou que era uma boa idéia camelCase os equivalentes JavaScript dos atributos HTML. Não consegui encontrar nenhuma especificação para isso, mas a rede parece concordar que se trata de 12 casos específicos (pelo menos para o HTML 4). Veja, por exemplo, o seguinte post: drupal.org/node/1420706#comment-6423420
usemap
atributo não pode ser definido usando a notação de ponto ao criar o mapa dinamicamente para uma imagem. Requer img.setAttribute('usemap', "#MapName");
Sua resposta implica que usemap
é, portanto, "fora do padrão"?
Nenhuma das respostas anteriores está completa e a maioria contém informações erradas.
Existem três maneiras de acessar os atributos de um DOM elemento em JavaScript. Todos os três funcionam de maneira confiável nos navegadores modernos, desde que você saiba como utilizá-los.
element.attributes
Os elementos têm atributos de propriedade que retornam um NamedNodeMap de objetos Attr ativos . Os índices desta coleção podem ser diferentes entre os navegadores. Portanto, o pedido não é garantido. NamedNodeMap
possui métodos para adicionar e remover atributos ( getNamedItem
esetNamedItem
, respectivamente).
Observe que, embora o XML seja explicitamente sensível a maiúsculas e minúsculas, a especificação do DOM solicita que os nomes de cadeias sejam normalizados ; portanto, os nomes passados getNamedItem
são efetivamente sem distinção entre maiúsculas e 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
Esses métodos existem diretamente no Element
sem a necessidade de acessar attributes
e seus métodos, mas executam as mesmas funções.
Novamente, observe que o nome da string não diferencia maiúsculas de 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
Muitos atributos podem ser acessados usando propriedades convenientes no objeto DOM. Quais atributos existem dependem do tipo do nó DOM, não quais atributos são definidos no HTML. As propriedades são definidas em algum lugar da cadeia de protótipos do objeto DOM em questão. As propriedades específicas definidas dependerão do tipo de elemento que você está acessando. Por exemplo, className
e id
são definidos Element
e existem em todos os nós do DOM que são elementos ( por exemplo, não nós de texto ou comentário). Mas value
é mais estreito. Está definido HTMLInputElement
e pode não existir em outros elementos.
Observe que as propriedades do JavaScript diferenciam maiúsculas de minúsculas. Embora a maioria das propriedades use letras minúsculas, algumas são camelCase. Portanto, sempre verifique as especificações para ter certeza.
Este "gráfico" captura uma parte da cadeia de protótipos para esses objetos DOM. Não está nem perto de terminar, mas captura a estrutura geral.
____________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>
Advertência: Esta é uma explicação de como a especificação HTML define e os navegadores modernos lidam com atributos. Não tentei lidar com as limitações de navegadores antigos e quebrados. Se você precisar oferecer suporte a navegadores antigos, além dessas informações, precisará saber o que está quebrado nesses navegadores.
Um caso que descobri onde setAttribute
é necessário é ao alterar os atributos do ARIA, pois não há propriedades correspondentes. Por exemplo
x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');
Não há x.arialabel
nada disso, então você precisa usar o setAttribute.
Edit: x ["aria-label"] não funciona . Você realmente precisa 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"
Essas respostas não estão realmente abordando a grande confusão entre propriedades e atributos . Além disso, dependendo do protótipo Javascript, às vezes você pode usar a propriedade de um elemento para acessar um atributo e às vezes não.
Primeiro, você deve se lembrar que an HTMLElement
é um objeto Javascript. Como todos os objetos, eles têm propriedades. Claro, você pode criar uma propriedade chamada quase tudo o que deseja dentro HTMLElement
, mas não precisa fazer nada com o DOM (o que está na página). A notação de ponto ( .
) é para propriedades . Agora, existem algumas propriedades especiais que são mapeadas para atributos e, no momento ou por escrito, existem apenas 4 garantidas (mais sobre isso posteriormente).
Todos os HTMLElement
s incluem uma propriedade chamada attributes
. HTMLElement.attributes
é uma vivo NamedNodeMap
objecto que se relaciona com os elementos no DOM. "Ao vivo" significa que quando o nó muda no DOM, eles mudam no lado do JavaScript e vice-versa. Os atributos DOM, nesse caso, são os nós em questão. A Node
possui uma .nodeValue
propriedade que você pode alterar. NamedNodeMap
objetos têm uma função chamada setNamedItem
onde você pode alterar o nó inteiro. Você também pode acessar diretamente o nó pela chave. Por exemplo, você pode dizer .attributes["dir"]
qual é o mesmo que .attributes.getNamedItem('dir');
(Nota lateral, não NamedNodeMap
diferencia maiúsculas de minúsculas, para que você também possa passar 'DIR'
);
Existe uma função semelhante diretamente na HTMLElement
qual você pode simplesmente chamar, setAttribute
que criará automaticamente um nó se ele não existir e definirá o nodeValue
. Também existem alguns atributos aos quais você pode acessar diretamente como propriedades por HTMLElement
meio de propriedades especiais , como dir
. Aqui está um mapeamento aproximado da aparência:
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 || ''
}
Então você pode alterar os dir
atributos de 6 maneiras:
// 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';
Você pode atualizar todas as propriedades com métodos # 1-5, mas apenas dir
, id
, lang
, e className
com o método # 6.
HTMLElement
tem essas 4 propriedades especiais. Alguns elementos são classes estendidas de HTMLElement
propriedades ainda mais mapeadas. Por exemplo, HTMLAnchorElement
tem HTMLAnchorElement.href
, HTMLAnchorElement.rel
e HTMLAnchorElement.target
. Mas, cuidado , se você definir essas propriedades em elementos que não possuem essas propriedades especiais (como em a HTMLTableElement
), os atributos não serão alterados e serão apenas propriedades personalizadas normais. Para entender melhor, aqui está um exemplo de sua herança:
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 || ''
}
Agora, o grande aviso: como todos os objetos Javascript , você pode adicionar propriedades personalizadas. Mas isso não muda nada no DOM. Você pode fazer:
const newElement = document.createElement('div');
// THIS WILL NOT CHANGE THE ATTRIBUTE
newElement.display = 'block';
Mas é o mesmo que
newElement.myCustomDisplayAttribute = 'block';
Isso significa que a adição de uma propriedade customizada não será vinculada.attributes[attr].nodeValue
.
atuação
Criei um caso de teste jsperf para mostrar a diferença: https://jsperf.com/set-attribute-comparison . Basicamente, em ordem:
dir
, id
, className
).element.attributes.ATTRIBUTENAME.nodeValue =
element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
element.attributes.ATTRIBUTENAME = newNode
element.attributes.setNamedItem(ATTRIBUTENAME) = newNode
Conclusão (TL; DR)
Use os mapeamentos de propriedades especiais de HTMLElement
: element.dir
, element.id
, element.className
, ou element.lang
.
Se você tiver 100% de certeza de que o elemento é estendido HTMLElement
com uma propriedade especial, use esse mapeamento especial. (Você pode verificar com if (element instanceof HTMLAnchorElement)
).
Se você tem 100% de certeza de que o atributo já existe, use element.attributes.ATTRIBUTENAME.nodeValue = newValue
.
Caso contrário, use setAttribute()
.
classList
é 100% garantido que existe, mas não é uma propriedade de string, é um DOMTokenList
objeto ativo. Definir .className
diretamente é mais rápido do que manipular classList
, mas você substituirá a coisa toda.
.value
, altera o valor interno de HTMLInputElement
, que é refletido nos atributos. Eles também não precisam ser string
. .valueAsNumber
mudará value
internamente e sua string
forma aparecerá no value
atributo developer.mozilla.org/pt-BR/docs/Web/HTML/Attributes
"Quando usar setAttribute vs .attribute = em JavaScript?"
Uma regra geral é usar .attribute
e verificar se funciona no navegador.
..Se funcionar no navegador, você está pronto para ir.
..Se não, use em .setAttribute(attribute, value)
vez de .attribute
para esse atributo.
Repita a lavagem para todos os atributos.
Bem, se você é preguiçoso, pode simplesmente usar .setAttribute
. Isso deve funcionar bem na maioria dos navegadores. (Embora os navegadores compatíveis .attribute
possam otimizá-lo melhor que .setAttribute(attribute, value)
.)
Parece um caso em que é melhor 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
funciona em todos os navegadores (funcionou para mim no Firefox)? É apenas por razões de desempenho que setAttribute
é preferido, evitando os repain? É posElem.style.cssText = newStyle
mais perfomrant então posElem.style = newStyle
?
métodos para definir atributos (por exemplo, classe) em um elemento: 1. el.className = string 2. el.setAttribute ('class', string) 3. el.attributes.setNamedItem (objeto) 4. el.setAttributeNode (nó)
Fiz um teste simples de benchmark ( aqui )
e parece que setAttributeNode é cerca de três vezes mais rápido que o setAttribute.
portanto, se o desempenho for um problema - use "setAttributeNode"
Publicação interessante do script da API do Google sobre isso:
Eles fazem assim:
var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";
Observe como eles usam setAttribute
para "src" e "nonce", mas depois .async = ...
para o atributo "async".
Não tenho 100% de certeza, mas provavelmente é porque o "assíncrono" é suportado apenas em navegadores que suportam .attr =
atribuição direta . Portanto, não faz sentido tentar, sestAttribute("async")
porque se o navegador não entender.async=...
- ele não entenderá o atributo "async".
Felizmente, esse é um insight útil do meu projeto de pesquisa em andamento "Desminificar GAPI" . Corrija-me se eu estiver errado.
.setAttribute()
para[key] = value
, tudo começou a funcionar magicamente.