Existe-t-il un moyen d'ajouter / supprimer plusieurs classes en une seule instruction avec classList?

164

Jusqu'à présent, je dois faire ceci:

elem.classList.add("first");
elem.classList.add("second");
elem.classList.add("third");

Bien que cela soit faisable dans jQuery, comme ceci

$(elem).addClass("first second third");

J'aimerais savoir s'il existe un moyen natif d'ajouter ou de supprimer.

Tente Enrique Moreno
la source

Réponses:

315
elem.classList.add("first");
elem.classList.add("second");
elem.classList.add("third");

est égal

elem.classList.add("first","second","third");
iwege
la source
15
Et si vous voulez appliquer un tableau de plusieurs noms de classe, vous devez appeler: DOMTokenList.prototype.add.apply (elem.classList, ['first', 'second', 'third']);
Emanuel Kluge
8
Firefox ne le supporte pas non plus, au moment de la rédaction. Ma réponse fournit un polyfill.
Andy E
Je passe à celui-ci comme la bonne réponse, car il s'agit d'une API native, même si le support n'est pas excellent.
Enrique Moreno Tent le
1
Avez-vous envisagé el.className + = "mes cours ici"
Michael Tontchev
1
existe-t-il un moyen de supprimer plusieurs classes
MeVimalkumar
72

Le nouvel opérateur de diffusion facilite encore l'application de plusieurs classes CSS en tant que tableau:

const list = ['first', 'second', 'third'];
element.classList.add(...list);
morkro
la source
1
La réponse acceptée fonctionne avec une liste directe de valeurs, mais celle-ci fonctionne avec des tableaux ... les deux semblent d'excellentes réponses!
Enrique Moreno Tent
Puis-je utiliser un DOMTokenListau lieu d'un tableau? Je sais qu'un DOMTokenList est un objet de type tableau. Il est donc possible de l'utiliser avec la classList.add()méthode ou faut-il convertir le DOMTokenList en un vrai tableau?
xela84
19

La classListpropriété garantit que les classes dupliquées ne sont pas inutilement ajoutées à l'élément. Afin de conserver cette fonctionnalité, si vous n'aimez pas les versions longues ou la version jQuery, je vous suggère d'ajouter une addManyfonction et removeManyà DOMTokenList(le type de classList):

DOMTokenList.prototype.addMany = function(classes) {
    var array = classes.split(' ');
    for (var i = 0, length = array.length; i < length; i++) {
      this.add(array[i]);
    }
}

DOMTokenList.prototype.removeMany = function(classes) {
    var array = classes.split(' ');
    for (var i = 0, length = array.length; i < length; i++) {
      this.remove(array[i]);
    }
}

Ceux-ci seraient alors utilisables comme ceci:

elem.classList.addMany("first second third");
elem.classList.removeMany("first third");

Mettre à jour

Selon vos commentaires, si vous souhaitez écrire une méthode personnalisée pour ceux-ci uniquement dans le cas où ils ne sont pas définis, essayez ce qui suit:

DOMTokenList.prototype.addMany = DOMTokenList.prototype.addMany || function(classes) {...}
DOMTokenList.prototype.removeMany = DOMTokenList.prototype.removeMany || function(classes) {...}
Rich O'Kelly
la source
Encore une bonne réponse. Et je ne pouvais pas le modifier pour vous car il n'y avait que 2 caractères.
Pete
18

Puisque la add()méthode de classListjust permet de passer des arguments séparés et non un seul tableau, vous devez invoquer en add()utilisant apply. Pour le premier argument, vous devrez passer la classListréférence du même nœud DOM et comme second argument le tableau de classes que vous souhaitez ajouter:

element.classList.add.apply(
  element.classList,
  ['class-0', 'class-1', 'class-2']
);
Andrés Carreño
la source
C'est la version ES5 de la solution avec Spread Operator (voir la réponse @morkro ). Vérifiez-le facilement sur Babel Repl .
Nickensoul
7

Pour ajouter une classe à un élément

document.querySelector(elem).className+=' first second third';

METTRE À JOUR:

Supprimer une classe

document.querySelector(elem).className=document.querySelector(elem).className.split(class_to_be_removed).join(" ");

la source
C'est intéressant à savoir, mais il ne fait que modifier la chaîne de la classe. Cela ne fonctionnerait pas si je voulais supprimer plusieurs classes. Désolé, j'ai oublié d'ajouter cela dans l'OP.
Enrique Moreno Tent
4
Ne pas utiliser className. C'est terrible pour les performances (même récupérer sa valeur provoque une redistribution).
Jacob
7

Les versions plus récentes de la spécification DOMTokenList autorisent plusieurs arguments pour add()et remove(), ainsi qu'un deuxième argument toggle()pour forcer l'état.

Au moment de la rédaction de cet article, Chrome prend en charge plusieurs arguments pour add()et remove(), mais aucun des autres navigateurs ne le fait. IE 10 et inférieur, Firefox 23 et inférieur, Chrome 23 et inférieur et les autres navigateurs ne prennent pas en charge le deuxième argument de toggle().

J'ai écrit le petit polyfill suivant pour me guider jusqu'à ce que le support se développe:

(function () {
    /*global DOMTokenList */
    var dummy  = document.createElement('div'),
        dtp    = DOMTokenList.prototype,
        toggle = dtp.toggle,
        add    = dtp.add,
        rem    = dtp.remove;

    dummy.classList.add('class1', 'class2');

    // Older versions of the HTMLElement.classList spec didn't allow multiple
    // arguments, easy to test for
    if (!dummy.classList.contains('class2')) {
        dtp.add    = function () {
            Array.prototype.forEach.call(arguments, add.bind(this));
        };
        dtp.remove = function () {
            Array.prototype.forEach.call(arguments, rem.bind(this));
        };
    }

    // Older versions of the spec didn't have a forcedState argument for
    // `toggle` either, test by checking the return value after forcing
    if (!dummy.classList.toggle('class1', true)) {
        dtp.toggle = function (cls, forcedState) {
            if (forcedState === undefined)
                return toggle.call(this, cls);

            (forcedState ? add : rem).call(this, cls);
            return !!forcedState;
        };
    }
})();

Un navigateur moderne conforme à ES5 DOMTokenListest attendu, mais j'utilise ce polyfill dans plusieurs environnements spécifiquement ciblés, donc cela fonctionne très bien pour moi, mais il faudra peut-être peaufiner les scripts qui fonctionneront dans les environnements de navigateur hérités tels que IE 8 et les versions antérieures .

Andy E
la source
1
Personne ne semble mentionner qu'IE10 ne permet pas l'ajout de plusieurs classes. Cela a bien fonctionné pour moi alors merci! Je voudrais cependant avertir que dans IE9, j'obtiens une erreur indiquant que DomTokenList n'est pas défini. Vous voudrez peut-être en tenir compte également. Ou exécutez ceci seulement si (typeof DomTokenList! == 'undefined')
Ryan Ore
@Ryan: merci, je pensais que DOMTokenList était pris en charge dans IE 9 mais je suppose qu'il a été manqué. Je vais essayer d'étudier une solution de contournement à un moment donné.
Andy E
On dirait que sur une DOMTokenList échouée, vous devrez utiliser className avec des vérifications regEx de limite de mot
Greg
7

Vous pouvez faire comme ci-dessous

Ajouter

elem.classList.add("first", "second", "third");

Retirer

elem.classList.remove("first", "second", "third");

Référence

TLDR;

Dans le cas simple ci-dessus, la suppression devrait fonctionner. Mais en cas de suppression, vous devez vous assurer que la classe existe avant de les supprimer

const classes = ["first","second","third"];
classes.forEach(c => {
  if (elem.classList.contains(c)) {
     element.classList.remove(c);
  }
})
Pankaj Parkar
la source
5

Voici un travail autour des utilisateurs d'IE 10 et 11 qui semblait assez simple.

var elem = document.getElementById('elem');

['first','second','third'].map(item => elem.classList.add(item));
<div id="elem">Hello World!</div>

Ou

var elem = document.getElementById('elem'),
    classes = ['first','second','third'];

classes.map(function(item) {
    return elem.classList.add(item);
});
<div id="elem">Hello World!</div>

colecmc
la source
5
Bonne idée. J'utiliserais .forEach () au lieu de .map () - c'est plus propre / plus efficace pour des situations comme celle-ci où vous n'utilisez pas le tableau retourné.
tenni
Oui c'est vrai.
colecmc
2

La définition standard permet uniquement d'ajouter ou de supprimer une seule classe. Quelques petites fonctions de wrapper peuvent faire ce que vous demandez:

function addClasses (el, classes) {
  classes = Array.prototype.slice.call (arguments, 1);
  console.log (classes);
  for (var i = classes.length; i--;) {
    classes[i] = classes[i].trim ().split (/\s*,\s*|\s+/);
    for (var j = classes[i].length; j--;)
      el.classList.add (classes[i][j]);
  }
}

function removeClasses (el, classes) {
  classes = Array.prototype.slice.call (arguments, 1);
  for (var i = classes.length; i--;) {
    classes[i] = classes[i].trim ().split (/\s*,\s*|\s+/);
    for (var j = classes[i].length; j--;)
      el.classList.remove (classes[i][j]);
  }
}

Ces wrappers vous permettent de spécifier la liste des classes en tant qu'arguments séparés, sous forme de chaînes avec des éléments séparés par des espaces ou des virgules, ou une combinaison. Pour un exemple, voir http://jsfiddle.net/jstoolsmith/eCqy7

RAP
la source
2

Une solution très simple, non sophistiquée, mais fonctionnelle que je devrais croire est très multi-navigateur:

Créer cette fonction

function removeAddClasses(classList,removeCollection,addCollection){
    for (var i=0;i<removeCollection.length;i++){ 
        classList.remove(removeCollection[i]); 
    }
    for (var i=0;i<addCollection.length;i++){ 
        classList.add(addCollection[i]); 
    }
}

Appelez-le comme ceci: removeAddClasses (node.classList, arrayToRemove, arrayToAdd);

... où arrayToRemove est un tableau de noms de classes à supprimer: ['myClass1', 'myClass2'] etcetera

... et arrayToAdd est un tableau de noms de classes à ajouter: ['myClass3', 'myClass4'] etcetera

Soren
la source
1

Supposons que vous ayez un tableau de classes à ajouter, vous pouvez utiliser la syntaxe de diffusion ES6:

let classes = ['first', 'second', 'third']; elem.classList.add(...classes);

Dong Nguyen
la source
0

J'ai aimé la réponse de @ rich.kelly, mais je voulais utiliser la même nomenclature que classList.add()(chaînes séparées par des virgules), donc un léger écart.

DOMTokenList.prototype.addMany = DOMTokenList.prototype.addMany || function() {
  for (var i = 0; i < arguments.length; i++) {
    this.add(arguments[i]);
  }
}
DOMTokenList.prototype.removeMany = DOMTokenList.prototype.removeMany || function() {
  for (var i = 0; i < arguments.length; i++) {
    this.remove(arguments[i]);
  }
}

Vous pouvez donc utiliser:

document.body.classList.addMany('class-one','class-two','class-three');

Je dois tester tous les navigateurs, mais cela a fonctionné pour Chrome.
Devrions-nous vérifier quelque chose de plus spécifique que l'existence de DOMTokenList.prototype.addMany? Quelles sont exactement les causes classList.add()de l'échec dans IE11?

Jason Lydon
la source
0

Un autre polyfill pour element.classListest ici . Je l'ai trouvé via MDN .

J'inclus ce script et je l'utilise element.classList.add("first","second","third")comme prévu.

Rafi
la source