La proprietà Element.classList
di sola lettura restituisce una raccolta DOMTokenList
dinamica delle classi dell'elemento.
L'utilizzo di classList
è una comoda alternativa all'accesso all'elenco di classi di un elemento come stringa delimitata dallo spazio tramite element.className
.
Sintassi
const elementClasses = elementNodeReference.classList;
elementClasses è una DOMTokenList
che rappresenta l'attributo class di elementNodeReference. Se l'attributo class non è stato impostato o è vuoto elementClasses.length ritorna 0
. element.classList
è di sola lettura, sebbene sia possibile modificarlo utilizzando i metodi add()
e remove()
.
Metodi
add( String [, String [, ...]] )
- Aggiunge le classi specificate. Se queste classi esistono già nell'attributo
class
dell'elemento, vengono ignorate. remove( String [, String [, ...]] )
-
Rimuove le classi specificate.
Nota: La rimozione di una classe inesistente NON genera un errore. item( Number )
- Restituisce il valore della classe per indice nella collezione.
toggle( String [, force] )
- Quando è presente un solo argomento: aggiunge/rimuove il valore della classe; ad esempio, se la classe esiste, la rimuove e restituisce
false
, altrimenti, la aggiunge e restituiscetrue
.
Quando è presente un secondo argomento: Se il secondo argomento restituiscetrue
, aggiunge la classe specificata; se restituiscefalse
, la rimuove. contains( String )
- Verifica se il valore di classe specificato esiste nell'attributo
class
dell'elemento. replace( vecchiaClasse, nuovaClasse )
- Sostituisce una classe esistente con una nuova classe.
Esempi
const div = document.createElement('div');
div.className = 'foo';
// il nostro stato iniziale: <div class="foo"></div>
console.log(div.outerHTML);
// usare l'API classList per rimuovere e aggiungere classi
div.classList.remove("foo");
div.classList.add("anotherclass");
// <div class="anotherclass"></div>
console.log(div.outerHTML);
// se visible è impostato rimuovilo, altrimenti aggiungilo
div.classList.toggle("visible");
// aggiungi/rimuovi visible, a seconda del test condizionale, i meno di 10
div.classList.toggle("visible", i < 10 );
console.log(div.classList.contains("foo"));
// aggiungere o rimuovere più classi
div.classList.add("foo", "bar", "baz");
div.classList.remove("foo", "bar", "baz");
// aggiungere o rimuovere più classi utilizzando la spread syntax
const cls = ["foo", "bar"];
div.classList.add(...cls);
div.classList.remove(...cls);
// sostituire la classe "foo" con la classe "bar"
div.classList.replace("foo", "bar");
Le versioni di Firefox precedenti alla 26 non implementano l'uso di diversi argomenti nei metodi add/remove/toggle. Vedi https://bugzilla.mozilla.org/show_bug.cgi?id=814014
Polyfill
L'evento legacy onpropertychange
può essere utilizzato per creare un mockup dinamico di classList
dinamico grazie alla proprietà Element.prototype.className
che attiva l'evento specificato una volta modificato.
Il seguente polyfill sia per classList
che per DOMTokenList
garantisce la piena conformità (copertura) per tutti i metodi e le proprietà standard di Element.prototype.classList
per i browser IE10-IE11 oltre ad un comportamento quasi conforme per IE 6-9. Controlla:
// 1. String.prototype.trim polyfill
if (!"".trim) String.prototype.trim = function(){ return this.replace(/^[\s]+|[\s]+$/g, ''); };
(function(window){"use strict"; // prevent global namespace pollution
if(!window.DOMException) (DOMException = function(reason){this.message = reason}).prototype = new Error;
var wsRE = /[\11\12\14\15\40]/, wsIndex = 0, checkIfValidClassListEntry = function(O, V) {
if (V === "") throw new DOMException(
"Failed to execute '" + O + "' on 'DOMTokenList': The token provided must not be empty." );
if((wsIndex=V.search(wsRE))!==-1) throw new DOMException("Failed to execute '"+O+"' on 'DOMTokenList': " +
"The token provided ('"+V[wsIndex]+"') contains HTML space characters, which are not valid in tokens.");
}
// 2. Implement the barebones DOMTokenList livelyness polyfill
if (typeof DOMTokenList !== "function") (function(window){
var document = window.document, Object = window.Object, hasOwnProp = Object.prototype.hasOwnProperty;
var defineProperty = Object.defineProperty, allowTokenListConstruction = 0, skipPropChange = 0;
function DOMTokenList(){
if (!allowTokenListConstruction) throw TypeError("Illegal constructor"); // internally let it through
}
DOMTokenList.prototype.toString = DOMTokenList.prototype.toLocaleString = function(){return this.value};
DOMTokenList.prototype.add = function(){
a: for(var v=0, argLen=arguments.length,val="",ele=this[" uCL"],proto=ele[" uCLp"]; v!==argLen; ++v) {
val = arguments[v] + "", checkIfValidClassListEntry("add", val);
for (var i=0, Len=proto.length, resStr=val; i !== Len; ++i)
if (this[i] === val) continue a; else resStr += " " + this[i];
this[Len] = val, proto.length += 1, proto.value = resStr;
}
skipPropChange = 1, ele.className = proto.value, skipPropChange = 0;
};
DOMTokenList.prototype.remove = function(){
for (var v=0, argLen=arguments.length,val="",ele=this[" uCL"],proto=ele[" uCLp"]; v !== argLen; ++v) {
val = arguments[v] + "", checkIfValidClassListEntry("remove", val);
for (var i=0, Len=proto.length, resStr="", is=0; i !== Len; ++i)
if(is){ this[i-1]=this[i] }else{ if(this[i] !== val){ resStr+=this[i]+" "; }else{ is=1; } }
if (!is) continue;
delete this[Len], proto.length -= 1, proto.value = resStr;
}
skipPropChange = 1, ele.className = proto.value, skipPropChange = 0;
};
window.DOMTokenList = DOMTokenList;
function whenPropChanges(){
var evt = window.event, prop = evt.propertyName;
if ( !skipPropChange && (prop==="className" || (prop==="classList" && !defineProperty)) ) {
var target = evt.srcElement, protoObjProto = target[" uCLp"], strval = "" + target[prop];
var tokens=strval.trim().split(wsRE), resTokenList=target[prop==="classList"?" uCL":"classList"];
var oldLen = protoObjProto.length;
a: for(var cI = 0, cLen = protoObjProto.length = tokens.length, sub = 0; cI !== cLen; ++cI){
for(var innerI=0; innerI!==cI; ++innerI) if(tokens[innerI]===tokens[cI]) {sub++; continue a;}
resTokenList[cI-sub] = tokens[cI];
}
for (var i=cLen-sub; i < oldLen; ++i) delete resTokenList[i]; //remove trailing indexs
if(prop !== "classList") return;
skipPropChange = 1, target.classList = resTokenList, target.className = strval;
skipPropChange = 0, resTokenList.length = tokens.length - sub;
}
}
function polyfillClassList(ele){
if (!ele || !("innerHTML" in ele)) throw TypeError("Illegal invocation");
ele.detachEvent( "onpropertychange", whenPropChanges ); // prevent duplicate handler infinite loop
allowTokenListConstruction = 1;
try{ function protoObj(){} protoObj.prototype = new DOMTokenList(); }
finally { allowTokenListConstruction = 0 }
var protoObjProto = protoObj.prototype, resTokenList = new protoObj();
a: for(var toks=ele.className.trim().split(wsRE), cI=0, cLen=toks.length, sub=0; cI !== cLen; ++cI){
for (var innerI=0; innerI !== cI; ++innerI) if (toks[innerI] === toks[cI]) { sub++; continue a; }
this[cI-sub] = toks[cI];
}
protoObjProto.length = cLen-sub, protoObjProto.value = ele.className, protoObjProto[" uCL"] = ele;
if (defineProperty) { defineProperty(ele, "classList", { // IE8 & IE9 allow defineProperty on the DOM
enumerable: 1, get: function(){return resTokenList},
configurable: 0, set: function(newVal){
skipPropChange = 1, ele.className = protoObjProto.value = (newVal += ""), skipPropChange = 0;
var toks = newVal.trim().split(wsRE), oldLen = protoObjProto.length;
a: for(var cI = 0, cLen = protoObjProto.length = toks.length, sub = 0; cI !== cLen; ++cI){
for(var innerI=0; innerI!==cI; ++innerI) if(toks[innerI]===toks[cI]) {sub++; continue a;}
resTokenList[cI-sub] = toks[cI];
}
for (var i=cLen-sub; i < oldLen; ++i) delete resTokenList[i]; //remove trailing indexs
}
}); defineProperty(ele, " uCLp", { // for accessing the hidden prototype
enumerable: 0, configurable: 0, writeable: 0, value: protoObj.prototype
}); defineProperty(protoObjProto, " uCL", {
enumerable: 0, configurable: 0, writeable: 0, value: ele
}); } else { ele.classList=resTokenList, ele[" uCL"]=resTokenList, ele[" uCLp"]=protoObj.prototype; }
ele.attachEvent( "onpropertychange", whenPropChanges );
}
try { // Much faster & cleaner version for IE8 & IE9:
// Should work in IE8 because Element.prototype instanceof Node is true according to the specs
window.Object.defineProperty(window.Element.prototype, "classList", {
enumerable: 1, get: function(val){
if (!hasOwnProp.call(this, "classList")) polyfillClassList(this);
return this.classList;
},
configurable: 0, set: function(val){this.className = val}
});
} catch(e) { // Less performant fallback for older browsers (IE 6-8):
window[" uCL"] = polyfillClassList;
// the below code ensures polyfillClassList is applied to all current and future elements in the doc.
document.documentElement.firstChild.appendChild(document.createElement('style')).styleSheet.cssText=(
'_*{x-uCLp:expression(!this.hasOwnProperty("classList")&&window[" uCL"](this))}' + // IE6
'[class]{x-uCLp/**/:expression(!this.hasOwnProperty("classList")&&window[" uCL"](this))}' //IE7-8
);
}
})(window);
// 3. Patch in unsupported methods in DOMTokenList
(function(DOMTokenListProto, testClass){
if (!DOMTokenListProto.item) DOMTokenListProto.item = function(i){
function NullCheck(n) {return n===void 0 ? null : n} return NullCheck(this[i]);
};
if (!DOMTokenListProto.toggle || testClass.toggle("a",0)!==false) DOMTokenListProto.toggle=function(val){
if (arguments.length > 1) return (this[arguments[1] ? "add" : "remove"](val), !!arguments[1]);
var oldValue = this.value;
return (this.remove(oldValue), oldValue === this.value && (this.add(val), true) /*|| false*/);
};
if (!DOMTokenListProto.replace || typeof testClass.replace("a", "b") !== "boolean")
DOMTokenListProto.replace = function(oldToken, newToken){
checkIfValidClassListEntry("replace", oldToken), checkIfValidClassListEntry("replace", newToken);
var oldValue = this.value;
return (this.remove(oldToken), this.value !== oldValue && (this.add(newToken), true));
};
if (!DOMTokenListProto.contains) DOMTokenListProto.contains = function(value){
for (var i=0,Len=this.length; i !== Len; ++i) if (this[i] === value) return true;
return false;
};
if (!DOMTokenListProto.forEach) DOMTokenListProto.forEach = function(f){
if (arguments.length === 1) for (var i = 0, Len = this.length; i !== Len; ++i) f( this[i], i, this);
else for (var i=0,Len=this.length,tArg=arguments[1]; i !== Len; ++i) f.call(tArg, this[i], i, this);
};
if (!DOMTokenListProto.entries) DOMTokenListProto.entries = function(){
var nextIndex = 0, that = this;
return {next: function() {
return nextIndex<that.length ? {value: [nextIndex, that[nextIndex]], done: false} : {done: true};
}};
};
if (!DOMTokenListProto.values) DOMTokenListProto.values = function(){
var nextIndex = 0, that = this;
return {next: function() {
return nextIndex<that.length ? {value: that[nextIndex], done: false} : {done: true};
}};
};
if (!DOMTokenListProto.keys) DOMTokenListProto.keys = function(){
var nextIndex = 0, that = this;
return {next: function() {
return nextIndex<that.length ? {value: nextIndex, done: false} : {done: true};
}};
};
})(window.DOMTokenList.prototype, window.document.createElement("div").classList);
})(window);
Avvertenze
Il polyfill ha funzionalità limitate. Al momento non è in grado di eseguire il polyfill fuori dagli elementi del documento (ad esempio elementi creati da document.createElement
prima di essere appesi su un nodo padre) in IE6-7.
Tuttavia, dovrebbe funzionare bene in IE9. Una discrepanza maggiore tra la versione polyfilled di classList
e le specifiche W3 è che per IE6-8, non esiste un modo per creare un oggetto immutabile (un oggetto le cui proprietà non possono essere modificate direttamente). In IE9, tuttavia, è possibile estendere il prototipo, congelando l'oggetto visibile e sovrascrivendo i metodi di proprietà native. Tuttavia, tali azioni non funzionerebbero in IE6-IE8 e, in IE9, rallenterebbero le prestazioni dell'intera pagina Web fino alla scansione di una lumaca, rendendo queste modifiche completamente impraticabili per questo polyfill.
Una nota minore è che in IE6-7, questo polyfill usa la proprietà window[" uCL"]
sull'oggetto window per comunicare con le espressioni CSS, la proprietà css x-uCLp
su tutti gli elementi e la proprietà element[" uCL"]
su tutti gli elementi per consentire la raccolta di garbadge e migliorare le prestazioni. In tutti i browser polyfilled (IE6-9), una proprietà aggiuntiva element[" uCLp"]
viene aggiunta all'elemento per garantire la prototipazione conforme agli standard e una proprietà DOMTokenList[" uCL"]
viene aggiunta ad ogni oggetto element["classList"]
per garantire che la DOMTokenList sia limitata al proprio elemento.
Specifiche
Specifica | Stato | Commento |
---|---|---|
DOM The definition of 'Element.classList' in that specification. |
Living Standard | Definizione iniziale |
DOM4 The definition of 'Element.classList' in that specification. |
Obsolete |
Compatibilità con i browser
BCD tables only load in the browser