Quando utilizzare setAttribute vs .attribute = in JavaScript?


234

È stata sviluppata una best practice sull'uso setAttributeinvece della dot not ( .) dell'attributo?

Per esempio:

myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");

o

myObj.className = "nameOfClass";
myObj.id = "someID";

1
Quando sono passato da .setAttribute()a [key] = value, tutto ha iniziato a funzionare magicamente.
Andrew,

Risposte:


73

Dovresti sempre usare il .attributemodulo 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/ setAttributequando si desidera gestire il DOM così com'è (ad es. Solo testo letterale). Browser diversi confondono i due. Vedi Modalità Quirks: attributo (in) compatibilità .


127
Questa risposta non è abbastanza chiara ... Non sento davvero di averlo ancora capito.
temporaneo

1
@Aerovistae - sono d'accordo con te su questo. Aggiunta una nuova risposta che si spera sia più chiara.
Olan,

1
Ma se vuoi influenzare il HTML interno dell'elemento, devi usare setAttribute ...
Michael

3
Vuoi dire outterHTML * :)
megawac

4
Ho scoperto che a.href restituisce l'URL completo, ma getAttribute ('href') restituisce esattamente cosa in quell'attributo (<a href = "/ help" ...).
Coniglio di plastica,

144

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 setAttributeper attributi non standard.

Esempio:

node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works

2
e inoltre, appare dopo l'ultimo setAttribute nel tuo esempio, node.frameborderNON è definito, quindi devi ottenereAttribute per recuperare il valore.
Michael

5
@Michael correct - se si utilizza setAttribute per impostare un valore, è necessario utilizzare getAttribute per recuperarlo.
olan,

3
Non c'è niente di sbagliato nell'impostazione frameBorderdiretta, 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
aaaaaaaaaaaa

1
L' usemapattributo 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"?
mseifert,

1
Questo per lo più sbagliato. Alcuni attributi hanno proprietà definite, quindi no. Si tratta solo di come hanno scritto le specifiche. Non ha nulla a che fare con gli attributi standard o no. Tuttavia, è vero che nessuna proprietà standard può essere raggiunta solo con getAttribute ().
Ben,

79

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.

1. 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. NamedNodeMapha metodi per aggiungere e rimuovere attributi ( getNamedIteme 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 getNamedItemfanno distinzione tra maiuscole e minuscole.

Esempio di utilizzo:

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>

2. element.getAttribute&element.setAttribute

Questi metodi esistono direttamente sul Elementsenza la necessità di accedere attributese i suoi metodi ma svolgono le stesse funzioni.

Ancora una volta, nota che il nome della stringa non fa distinzione tra maiuscole e minuscole.

Esempio di utilizzo:

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>

3. Proprietà sull'oggetto DOM, ad esempio 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, classNamee idsono definiti Elemented esistono su tutti i nodi DOM che sono elementi (cioè non nodi di testo o di commento). Ma valueè più stretto. È definito HTMLInputElemente 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

Esempio di utilizzo:

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.


Grazie per il chiarimento. Sono curioso, quali versioni di IE sono considerate "moderne" e seguono le specifiche HTML?
jkdev,

3
@jkdev IE non è mai moderno. Che cosa mai diventa vecchio.
Suraj Jain,

Grazie per una risposta così dettagliata, ho letto molto sul DOM e sull'eredità come HTMLElement eredita da Element e così via, la tua risposta ha perfettamente senso.
Suraj Jain,

16

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.arialabelniente 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"

in realtà non proprio in Javascript puoi farlo x ["aria-label"]
Fareed Alnamrouti

@fareednamrouti che non funziona. L'ho appena provato. Le proprietà JS non influiscono sugli attributi html. Hai davvero bisogno di setAttribute qui.
Antimonio

@Antimonio Questo è strano ma sì, hai ragione al 100%, voterò in su
Fareed Alnamrouti,

2
Sei sicuro che non ci sia ariaLabel?
jgmjgm,

8

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 HTMLElementincludono 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 Nodeha una .nodeValueproprietà che puoi modificare. NamedNodeMapgli oggetti hanno una funzione chiamata in setNamedItemcui è 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 NamedNodeMapfa distinzione tra maiuscole e minuscole, quindi puoi anche passare 'DIR');

C'è una funzione simile direttamente in HTMLElementcui puoi semplicemente chiamare setAttributeche creerà automaticamente un nodo se non esiste e imposta il nodeValue. Ci sono anche alcuni attributi a cui puoi accedere direttamente come proprietà HTMLElementtramite 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 dirattributi 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 classNamecon il metodo # 6.

Estensioni di HTMLElement

HTMLElementha quelle 4 proprietà speciali. Alcuni elementi sono classi estese di HTMLElementproprietà ancora più mappate. Ad esempio, HTMLAnchorElementha HTMLAnchorElement.href, HTMLAnchorElement.rele 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 || '' 
}

Proprietà personalizzate

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:

  1. Proprietà personalizzate perché non influiscono sul DOM e non sono attributi .
  2. Mappature speciali forniti dal browser ( dir, id, className).
  3. Se gli attributi esistono già ,element.attributes.ATTRIBUTENAME.nodeValue =
  4. setAttribute ();
  5. Se gli attributi esistono già ,element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
  6. element.attributes.ATTRIBUTENAME = newNode
  7. 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 HTMLElementcon 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().


Hai menzionato questi quattro mapping delle proprietà: dir, id, className e lang. Che dire di classList? ClassList è un mapping di proprietà garantito?
Barzee,

classListè garantito al 100%, ma non è una proprietà stringa, è un DOMTokenListoggetto live . L'impostazione .classNamediretta è più veloce della manipolazione classList, ma sovrascriveresti l'intera cosa.
ShortFuse

Che ne dici di .value sui tag <input> e <textarea>? Di che tipo sono?
Daniel Williams,

Quelli menzionati nella risposta sono ciò che W3C chiama "riflettendo gli attributi IDL". Quando cambi .value, stai cambiando il valore interno di HTMLInputElement, che si riflette poi sugli attributi. Inoltre non devono essere string. .valueAsNumbercambierà value internamente e la sua stringforma apparirà valuenell'attributo. developer.mozilla.org/en-US/docs/Web/HTML/Attributes
ShortFuse

3

"Quando utilizzare setAttribute vs .attribute = in JavaScript?"

Una regola generale è quella di utilizzare .attributee verificare se funziona sul browser.

..Se funziona sul browser, sei a posto.

..Se non è così, usa .setAttribute(attribute, value)invece .attributeper 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 .attributepossono ottimizzarlo meglio di .setAttribute(attribute, value).)


0

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);
}

2
Grazie per aver condiviso questo tomo7, potresti per favore spiegarci un po 'di più. Non posElem.style = newStylefunziona in tutti i browser (ha funzionato per me in Firefox)? È solo per motivi prestazionali che setAttributesi preferisce, evitando le trattenute? posElem.style.cssText = newStyleAllora è più perfetto posElem.style = newStyle?
Noitidart,

0

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"


Penso che tu abbia eseguito il test su Chrome. Ho provato sul mio Mac usando Chrome, Safari e Firefox; si prevede che 3 di questi abbiano mostrato 3 risultati diversi.
Olgun Kaya,

0

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 setAttributeper "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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.