¿Hay alguna manera de agregar / eliminar varias clases en una sola instrucción con classList?

164

Hasta ahora tengo que hacer esto:

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

Si bien esto es factible en jQuery, así

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

Me gustaría saber si hay alguna forma nativa de agregar o eliminar.

Tienda Enrique Moreno
fuente

Respuestas:

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

es igual

elem.classList.add("first","second","third");
iwege
fuente
15
Y si desea aplicar una matriz de varios nombres de clase, debe llamar a: DOMTokenList.prototype.add.apply (elem.classList, ['first', 'second', 'third']);
Emanuel Kluge
8
Firefox tampoco lo admite, al momento de escribir. Mi respuesta proporciona un polyfill.
Andy E
Estoy cambiando a esta como la respuesta correcta, ya que esta es una API nativa, incluso si el soporte no es excelente.
Tienda de Enrique Moreno
1
¿Has considerado el.className + = "mis clases aquí"
Michael Tontchev
1
¿hay una manera de eliminar varias clases
MeVimalkumar
72

El nuevo operador de propagación hace que sea aún más fácil aplicar múltiples clases CSS como matriz:

const list = ['first', 'second', 'third'];
element.classList.add(...list);
morkro
fuente
1
La respuesta aceptada funciona con una lista directa de valores, pero esta funciona con matrices ... ¡ambas parecen respuestas excelentes!
Tienda Enrique Moreno
¿Puedo usar un en DOMTokenListlugar de una matriz? Sé que DOMTokenList es un objeto tipo matriz. Entonces, ¿es posible usarlo con el classList.add()método o debe DOMTokenList convertirse en una matriz real?
xela84
19

La classListpropiedad garantiza que las clases duplicadas no se agreguen innecesariamente al elemento. Con el fin de mantener esta funcionalidad, si no le gustan las versiones longhand o la versión de jQuery, me gustaría sugerir la adición de una addManyfunción y removeManyque DOMTokenList(el tipo 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]);
    }
}

Estos serían utilizables así:

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

Actualizar

Según sus comentarios, si solo desea escribir un método personalizado para estos en caso de que no estén definidos, intente lo siguiente:

DOMTokenList.prototype.addMany = DOMTokenList.prototype.addMany || function(classes) {...}
DOMTokenList.prototype.removeMany = DOMTokenList.prototype.removeMany || function(classes) {...}
Rich O'Kelly
fuente
Sigue siendo una buena respuesta. Y no pude editarlo ya que solo tenía 2 caracteres.
Pete
18

Dado que el add()método de classListjust permite pasar argumentos separados y no una sola matriz, debe invocar add()usando apply. Para el primer argumento, deberá pasar la classListreferencia desde el mismo nodo DOM y, como segundo argumento, la matriz de clases que desea agregar:

element.classList.add.apply(
  element.classList,
  ['class-0', 'class-1', 'class-2']
);
Andrés Carreño
fuente
Es la versión ES5 de la solución con el Operador Spread (ver respuesta @morkro ). Compruébelo fácilmente en Babel Repl .
Nickensoul
7

Para agregar clase a un elemento

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

ACTUALIZAR:

Eliminar una clase

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

fuente
Es interesante saber esto, pero todo lo que hace es editar la cadena de la clase. No funcionaría si quisiera eliminar varias clases. Lo siento, olvidé agregar eso en el OP.
Tienda de Enrique Moreno
44
No NO utilizar className. Es terrible para el rendimiento (incluso recuperar su valor provoca un reflujo).
jacob
7

Las versiones más nuevas de la especificación DOMTokenList permiten múltiples argumentos para add()y remove(), así como un segundo argumento toggle()para forzar el estado.

Al momento de escribir, Chrome admite múltiples argumentos para add()y remove(), pero ninguno de los otros navegadores lo hace. IE 10 y versiones inferiores, Firefox 23 y versiones inferiores, Chrome 23 y versiones inferiores y otros navegadores no admiten el segundo argumento toggle().

Escribí el siguiente pequeño polyfill para ayudarme hasta que el soporte se expanda:

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

Se DOMTokenListespera un navegador moderno con cumplimiento de ES5 , pero estoy usando este polyfill en varios entornos específicamente dirigidos, por lo que funciona muy bien para mí, pero podría necesitar ajustes para los scripts que se ejecutarán en entornos de navegador heredados como IE 8 y versiones anteriores .

Andy E
fuente
1
Nadie parece mencionar que IE10 no permite agregar múltiples clases. Esto funcionó muy bien para mí, así que gracias! Sin embargo, advierto que en IE9 me sale un error que DomTokenList no está definido. Es posible que desee dar cuenta de eso también. O solo ejecute esto si (typeof DomTokenList! == 'undefined')
Ryan Ore
@ Ryan: gracias, pensé que DOMTokenList era compatible con IE 9 pero supongo que se perdió. Intentaré investigar una solución en algún momento.
Andy E
Parece que en una DOMTokenList fallida tendrías que usar className con verificaciones de límites de palabras regEx
Greg
7

Puedes hacer lo siguiente

Añadir

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

Eliminar

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

Referencia

TLDR;

En caso directo, la eliminación anterior debería funcionar. Pero en caso de eliminación, debe asegurarse de que exista la clase antes de eliminarlos

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

Aquí hay una solución para usuarios de IE 10 y 11 que parecía bastante sencilla.

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

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

O

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
fuente
55
Buena idea. Sin embargo, usaría .forEach () en lugar de .map (): es más limpio / más eficiente para situaciones como esta en las que no está utilizando la matriz devuelta.
tenni
Sí, eso es verdad.
colecmc
2

La definición estándar solo permite agregar o eliminar una sola clase. Un par de funciones de envoltura pequeñas pueden hacer lo que pides:

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

Estos contenedores le permiten especificar la lista de clases como argumentos separados, como cadenas con elementos separados por comas o espacios, o una combinación. Para ver un ejemplo, consulte http://jsfiddle.net/jstoolsmith/eCqy7

HBP
fuente
2

Una solución muy simple, no sofisticada, pero funcional que debería creer es un navegador cruzado:

Crea esta función

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

Llámalo así: removeAddClasses (node.classList, arrayToRemove, arrayToAdd);

... donde arrayToRemove es una matriz de nombres de clase para eliminar: ['myClass1', 'myClass2'] etcétera

... y arrayToAdd es una matriz de nombres de clase para agregar: ['myClass3', 'myClass4'] etcétera

Soren
fuente
1

Suponga que tiene una variedad de clases para agregar, puede usar la sintaxis de propagación ES6:

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

Dong Nguyen
fuente
0

Me gustó la respuesta de @ rich.kelly, pero quería usar la misma nomenclatura que classList.add()(cadenas separadas por comas), por lo que una ligera desviación.

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

Entonces puedes usar:

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

Necesito probar todos los navegadores, pero esto funcionó para Chrome.
¿Deberíamos estar buscando algo más específico que la existencia de DOMTokenList.prototype.addMany? ¿Qué hace exactamente classList.add()que falle en IE11?

Jason Lydon
fuente
0

Otro polyfill para element.classListestá aquí . Lo encontré a través de MDN .

Incluyo ese script y lo uso element.classList.add("first","second","third")como está previsto.

Rafi
fuente