Existe uma maneira de adicionar / remover várias classes em uma única instrução com classList?

164

Até agora eu tenho que fazer isso:

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

Embora isso seja possível no jQuery, assim

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

Gostaria de saber se existe alguma maneira nativa de adicionar ou remover.

Tenda Enrique Moreno
fonte

Respostas:

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

é igual

elem.classList.add("first","second","third");
iwege
fonte
15
E se você deseja aplicar uma matriz de vários nomes de classe, é necessário chamar: DOMTokenList.prototype.add.apply (elem.classList, ['first', 'second', 'third']);
Emanuel Kluge
8
O Firefox também não é compatível no momento da redação. Minha resposta fornece um polyfill.
Andy E
Estou mudando para esta como a resposta correta, pois essa é uma API nativa, mesmo que o suporte não seja ótimo.
Enrique Moreno Tent
1
Você considerou el.className + = "minhas aulas aqui"
Michael Tontchev 27/03
1
há uma maneira para remover várias classes
MeVimalkumar
72

O novo operador de spread facilita ainda mais a aplicação de várias classes CSS como matriz:

const list = ['first', 'second', 'third'];
element.classList.add(...list);
morkro
fonte
1
A resposta aceita funciona com uma lista direta de valores, mas esta funciona com matrizes ... ambas parecem excelentes respostas!
Enrique Moreno Tent
Posso usar um em DOMTokenListvez de uma matriz? Eu sei que um DOMTokenList é um objeto de matriz. Portanto, é possível usá-lo com o classList.add()método ou o DOMTokenList deve ser convertido em uma matriz real?
Xela84 21/03/19
19

A classListpropriedade garante que classes duplicadas não sejam adicionadas desnecessariamente ao elemento. A fim de manter essa funcionalidade, se você não gosta das versões longhand ou versão jQuery, eu sugiro a adição de uma addManyfunção e removeManypara DOMTokenList(o 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]);
    }
}

Estes seriam então utilizáveis ​​da seguinte forma:

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

Atualizar

De acordo com seus comentários, se você deseja escrever apenas um método personalizado para eles, caso eles não sejam definidos, tente o seguinte:

DOMTokenList.prototype.addMany = DOMTokenList.prototype.addMany || function(classes) {...}
DOMTokenList.prototype.removeMany = DOMTokenList.prototype.removeMany || function(classes) {...}
Rich O'Kelly
fonte
Ainda é uma boa resposta. E não pude editá-lo para você, pois eram apenas dois caracteres.
Pete
18

Como o add()método da classListjust permite passar argumentos separados e não uma única matriz, você precisa invocar add()usando apply. Para o primeiro argumento, você precisará passar a classListreferência do mesmo nó DOM e, como segundo argumento, a matriz de classes que você deseja adicionar:

element.classList.add.apply(
  element.classList,
  ['class-0', 'class-1', 'class-2']
);
Andrés Carreño
fonte
É a versão ES5 da solução com o Spread Operator (consulte a resposta do @morkro ). Verifique-o facilmente em Babel Repl .
Nickensoul 15/05/19
7

Para adicionar classe a um elemento

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

ATUALIZAR:

Remover uma turma

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

fonte
É interessante saber isso, mas tudo o que faz é editar a sequência da classe. Não funcionaria se eu quisesse remover várias classes. Desculpe, esqueci de adicionar isso no OP.
Enrique Moreno Tent
4
Você não usar className. É terrível para o desempenho (mesmo recuperar seu valor causa um reflow).
11246
7

As versões mais recentes da especificação DOMTokenList permitem vários argumentos para add()e remove(), assim como um segundo argumento toggle()para forçar o estado.

No momento da redação deste artigo, o Chrome suporta vários argumentos para add()e remove(), mas nenhum dos outros navegadores suporta . IE 10 e inferior, Firefox 23 e inferior, Chrome 23 e inferior e outros navegadores não suportam o segundo argumento para toggle().

Escrevi o seguinte pequeno polyfill para me manter aquecido até que o suporte 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;
        };
    }
})();

Um navegador moderno com conformidade com o ES5 e DOMTokenListé esperado, mas eu estou usando esse polyfill em vários ambientes especificamente direcionados, por isso funciona muito bem para mim, mas pode precisar de ajustes para scripts que serão executados em ambientes de navegador herdados, como o IE 8 e versões inferiores. .

Andy E
fonte
1
Parece que ninguém mencionou que o IE10 não permite a adição de várias classes. Isso funcionou muito bem para mim, então obrigado! Eu recomendaria, no entanto, que no IE9, recebo um erro que DomTokenList não está definido. Você também pode dar conta disso. Ou só correr esse if (typeof DomTokenList == 'indefinido'!)
Ryan Ore
@ Ryan: obrigado, pensei que o DOMTokenList fosse suportado no IE 9, mas acho que foi perdido. Vou tentar investigar uma solução alternativa em algum momento.
Andy E
Parece que, em um DOMTokenList com falha, você teria que usar className com o limite de palavras regEx checks
Greg
7

Você pode fazer como abaixo

Adicionar

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

Remover

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

Referência

TLDR;

No caso direto acima, a remoção deve funcionar. Mas em caso de remoção, verifique se a classe existe antes de removê-las

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

Aqui está uma solução para os usuários do IE 10 e 11 que pareciam bastante diretos.

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
fonte
5
Boa ideia. Eu usaria .forEach () em vez de .map () - é mais limpo / mais eficiente para situações como esta em que você não está usando a matriz retornada.
Tenni #
Sim, é verdade.
Colecmc
2

A definição padrão permite apenas adicionar ou excluir uma única classe. Algumas pequenas funções do invólucro podem fazer o que você pede:

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

Esses wrappers permitem especificar a lista de classes como argumentos separados, como cadeias com itens separados por espaço ou vírgula ou uma combinação. Para um exemplo, consulte http://jsfiddle.net/jstoolsmith/eCqy7

HBP
fonte
2

Uma solução muito simples, não sofisticada, mas funcional, que eu teria que acreditar é muito diferente do navegador:

Crie esta função

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

Chame assim: removeAddClasses (node.classList, arrayToRemove, arrayToAdd);

... onde arrayToRemove é uma matriz de nomes de classe para remover: ['myClass1', 'myClass2'] etc.

... e arrayToAdd é uma matriz de nomes de classe para adicionar: ['myClass3', 'myClass4'] etc.

Soren
fonte
1

Suponha que você tenha uma matriz de classes a ser adicionada, você pode usar a sintaxe de expansão ES6:

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

Dong Nguyen
fonte
0

Gostei da resposta de @ rich.kelly, mas queria usar a mesma nomenclatura de classList.add()(strings separadas por vírgula), portanto, um pequeno desvio.

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

Então você pode usar:

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

Preciso testar todos os navegadores, mas isso funcionou para o Chrome.
Deveríamos procurar algo mais específico do que a existência de DOMTokenList.prototype.addMany? O que exatamente causa classList.add()uma falha no IE11?

Jason Lydon
fonte
0

Outro polyfill para element.classListestá aqui . Encontrei-o via MDN .

Incluo esse script e o uso element.classList.add("first","second","third")como pretendido.

Rafi
fonte