Risposte:
Dovresti sempre usare il .attribute
modulo diretto (ma vedi il link quirksmode di seguito) se vuoi un accesso programmatico in JavaScript. Dovrebbe gestire correttamente i diversi tipi di attributi (pensa "onload").
Utilizzare getAttribute
/ setAttribute
quando si desidera gestire il DOM così com'è (ad es. Solo testo letterale). Browser diversi confondono i due. Vedi Modalità Quirks: attributo (in) compatibilità .
Da Javascript: la guida definitiva , chiarisce le cose. Nota che gli oggetti HTMLElement di un documento HTML definiscono le proprietà JS che corrispondono a tutti gli attributi HTML standard.
Quindi è necessario utilizzare solo setAttribute
per attributi non standard.
Esempio:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
node.frameborder
NON è definito, quindi devi ottenereAttribute per recuperare il valore.
frameBorder
diretta, ma nota la maiuscola. Qualcuno ha pensato che fosse una buona idea jolly camelCase gli equivalenti JavaScript degli attributi HTML. Non sono riuscito a trovare alcuna specifica per questo, ma la rete sembra concordare sul fatto che si tratti di 12 casi specifici (almeno per HTML 4). Vedi ad esempio il seguente post: drupal.org/node/1420706#comment-6423420
usemap
attributo non può essere impostato usando la notazione punto durante la creazione dinamica della mappa per un'immagine. Richiede img.setAttribute('usemap', "#MapName");
La tua risposta implica che usemap
è quindi "non standard"?
Nessuna delle risposte precedenti è completa e la maggior parte contiene informazioni errate.
Esistono tre modi per accedere agli attributi di un elemento DOM in JavaScript. Tutti e tre funzionano in modo affidabile nei browser moderni, purché si capisca come utilizzarli.
element.attributes
Gli elementi hanno attributi di proprietà che restituiscono una NamedNodeMap attiva degli oggetti Attr . Gli indici di questa raccolta potrebbero essere diversi tra i browser. Quindi, l'ordine non è garantito. NamedNodeMap
ha metodi per aggiungere e rimuovere attributi ( getNamedItem
e setNamedItem
, rispettivamente).
Si noti che sebbene XML faccia esplicitamente distinzione tra maiuscole e minuscole, la specifica DOM richiede che i nomi delle stringhe vengano normalizzati , quindi i nomi passati non getNamedItem
fanno distinzione tra maiuscole e minuscole.
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
Questi metodi esistono direttamente sul Element
senza la necessità di accedere attributes
e i suoi metodi ma svolgono le stesse funzioni.
Ancora una volta, nota che il nome della stringa non fa distinzione tra maiuscole e minuscole.
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
È possibile accedere a molti attributi utilizzando comode proprietà sull'oggetto DOM. Quali attributi esistono dipendono dal tipo di nodo DOM, non da quali attributi sono definiti nell'HTML. Le proprietà sono definite da qualche parte nella catena di prototipi dell'oggetto DOM in questione. Le proprietà specifiche definite dipenderanno dal tipo di elemento a cui si accede. Ad esempio, className
e id
sono definiti Element
ed esistono su tutti i nodi DOM che sono elementi (cioè non nodi di testo o di commento). Ma value
è più stretto. È definito HTMLInputElement
e potrebbe non esistere su altri elementi.
Si noti che le proprietà JavaScript fanno distinzione tra maiuscole e minuscole. Anche se la maggior parte delle proprietà utilizzerà lettere minuscole, alcune sono camelCase. Quindi controlla sempre le specifiche per essere sicuro.
Questo "grafico" cattura una parte della catena prototipo per questi oggetti DOM. Non è nemmeno vicino al completamento, ma cattura la struttura generale.
____________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>
Avvertenza: questa è una spiegazione di come definiscono le specifiche HTML e i browser moderni gestiscono gli attributi. Non ho tentato di affrontare i limiti dei browser antichi e rotti. Se è necessario supportare i browser precedenti, oltre a queste informazioni, è necessario sapere cosa non funziona in tali browser.
Un caso che ho trovato dove setAttribute
è necessario è quando si cambiano gli attributi ARIA, poiché non ci sono proprietà corrispondenti. Per esempio
x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');
Non c'è x.arialabel
niente del genere, quindi devi usare setAttribute.
Modifica: x ["aria-label"] non funziona . Hai davvero bisogno di 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"
Queste risposte non affrontano realmente la grande confusione tra proprietà e attributi . Inoltre, a seconda del prototipo Javascript, a volte è possibile utilizzare la proprietà di un elemento per accedere a un attributo, a volte no.
Innanzitutto, devi ricordare che an HTMLElement
è un oggetto Javascript. Come tutti gli oggetti, hanno proprietà. Certo, puoi creare una proprietà chiamata quasi tutto quello che vuoi all'interno HTMLElement
, ma non deve fare nulla con il DOM (cosa c'è nella pagina). La notazione punto ( .
) è per le proprietà . Ora, ci sono alcune proprietà speciali che sono mappate agli attributi, e al momento o in scrittura ce ne sono solo 4 che sono garantite (ne parleremo più avanti).
Tutti HTMLElement
includono una proprietà chiamata attributes
. HTMLElement.attributes
è un oggetto live NamedNodeMap
che si riferisce agli elementi nel DOM. "In diretta" significa che quando il nodo cambia nel DOM, cambiano sul lato JavaScript e viceversa. Gli attributi DOM, in questo caso, sono i nodi in questione. A Node
ha una .nodeValue
proprietà che puoi modificare. NamedNodeMap
gli oggetti hanno una funzione chiamata in setNamedItem
cui è possibile cambiare l'intero nodo. È inoltre possibile accedere direttamente al nodo tramite la chiave. Ad esempio, puoi dire .attributes["dir"]
quale è lo stesso di .attributes.getNamedItem('dir');
(Nota a margine, non NamedNodeMap
fa distinzione tra maiuscole e minuscole, quindi puoi anche passare 'DIR'
);
C'è una funzione simile direttamente in HTMLElement
cui puoi semplicemente chiamare setAttribute
che creerà automaticamente un nodo se non esiste e imposta il nodeValue
. Ci sono anche alcuni attributi a cui puoi accedere direttamente come proprietà HTMLElement
tramite proprietà speciali , come dir
. Ecco una mappatura approssimativa di come appare:
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 || ''
}
Quindi puoi modificare gli dir
attributi in 6 modi:
// 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';
È possibile aggiornare tutte le proprietà con i metodi # 1-5, ma solo dir
, id
, lang
, e className
con il metodo # 6.
HTMLElement
ha quelle 4 proprietà speciali. Alcuni elementi sono classi estese di HTMLElement
proprietà ancora più mappate. Ad esempio, HTMLAnchorElement
ha HTMLAnchorElement.href
, HTMLAnchorElement.rel
e HTMLAnchorElement.target
. Ma attenzione , se si impostano quelle proprietà su elementi che non hanno quelle proprietà speciali (come su a HTMLTableElement
), gli attributi non vengono modificati e sono solo normali proprietà personalizzate. Per capire meglio, ecco un esempio della sua eredità:
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 || ''
}
Ora il grande avvertimento: come tutti gli oggetti Javascript , è possibile aggiungere proprietà personalizzate. Ma quelli non cambieranno nulla sul DOM. Tu puoi fare:
const newElement = document.createElement('div');
// THIS WILL NOT CHANGE THE ATTRIBUTE
newElement.display = 'block';
Ma è lo stesso di
newElement.myCustomDisplayAttribute = 'block';
Ciò significa che l'aggiunta di una proprietà personalizzata non verrà collegata.attributes[attr].nodeValue
.
Prestazione
Ho creato un caso di test jsperf per mostrare la differenza: https://jsperf.com/set-attribute-comparison . Fondamentalmente, per:
dir
, id
, className
).element.attributes.ATTRIBUTENAME.nodeValue =
element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
element.attributes.ATTRIBUTENAME = newNode
element.attributes.setNamedItem(ATTRIBUTENAME) = newNode
Conclusione (TL; DR)
Utilizzare i mapping delle proprietà speciali da HTMLElement
: element.dir
, element.id
, element.className
, o element.lang
.
Se sei sicuro al 100% che l'elemento sia esteso HTMLElement
con una proprietà speciale, usa quel mapping speciale. (Puoi verificare con if (element instanceof HTMLAnchorElement)
).
Se sei sicuro al 100% che l'attributo esiste già, usa element.attributes.ATTRIBUTENAME.nodeValue = newValue
.
In caso contrario, utilizzare setAttribute()
.
classList
è garantito al 100%, ma non è una proprietà stringa, è un DOMTokenList
oggetto live . L'impostazione .className
diretta è più veloce della manipolazione classList
, ma sovrascriveresti l'intera cosa.
.value
, stai cambiando il valore interno di HTMLInputElement
, che si riflette poi sugli attributi. Inoltre non devono essere string
. .valueAsNumber
cambierà value
internamente e la sua string
forma apparirà value
nell'attributo. developer.mozilla.org/en-US/docs/Web/HTML/Attributes
"Quando utilizzare setAttribute vs .attribute = in JavaScript?"
Una regola generale è quella di utilizzare .attribute
e verificare se funziona sul browser.
..Se funziona sul browser, sei a posto.
..Se non è così, usa .setAttribute(attribute, value)
invece .attribute
per quel attributo.
Risciacqua-ripeti per tutti gli attributi.
Bene, se sei pigro puoi semplicemente usare .setAttribute
. Questo dovrebbe funzionare bene sulla maggior parte dei browser. (Anche se i browser che supportano .attribute
possono ottimizzarlo meglio di .setAttribute(attribute, value)
.)
Questo sembra un caso in cui è meglio usare setAttribute:
Dev.Opera - JavaScript efficiente
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
funziona in tutti i browser (ha funzionato per me in Firefox)? È solo per motivi prestazionali che setAttribute
si preferisce, evitando le trattenute? posElem.style.cssText = newStyle
Allora è più perfetto posElem.style = newStyle
?
metodi per impostare gli attributi (ad esempio la classe) su un elemento: 1. el.className = string 2. el.setAttribute ('class', string) 3. el.attributes.setNamedItem (oggetto) 4. el.setAttributeNode (nodo)
Ho fatto un semplice test di riferimento ( qui )
e sembra che setAttributeNode sia circa 3 volte più veloce rispetto all'uso di setAttribute.
quindi se le prestazioni sono un problema - usa "setAttributeNode"
Interessante asporto dallo script dell'API di Google in merito a questo:
Lo fanno così:
var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";
Notate come usano setAttribute
per "src" e "nonce", ma poi .async = ...
per l'attributo "asincrono".
Non sono sicuro al 100%, ma probabilmente è perché "asincrono" è supportato solo su browser che supportano l' .attr =
assegnazione diretta . Quindi, non ha senso provare sestAttribute("async")
perché se il browser non capisce .async=...
, non capirà l'attributo "asincrono".
Spero che sia una visione utile del mio progetto di ricerca "Un-minify GAPI" in corso . Correggimi se sbaglio.
.setAttribute()
a[key] = value
, tutto ha iniziato a funzionare magicamente.