Remova todas as classes que começam com uma certa string

99

Eu tenho um div com id="a"que pode ter qualquer número de classes anexadas a ele, de vários grupos. Cada grupo possui um prefixo específico. No javascript, não sei qual turma do grupo está no div. Quero ser capaz de limpar todas as classes com um determinado prefixo e, em seguida, adicionar um novo. Se eu quiser remover todas as classes que começam com "bg", como faço isso? Algo assim, mas realmente funciona:

$("#a").removeClass("bg*");
Brad
fonte

Respostas:

59

Com jQuery, o elemento DOM real está no índice zero, isso deve funcionar

$('#a')[0].className = $('#a')[0].className.replace(/\bbg.*?\b/g, '');
Pat
fonte
34
Cuidado com este. O limite da palavra se divide no caractere de traço ('-') e pontos e outros, de modo que nomes de classe como "bg.a", "bg-a" etc. não serão removidos, mas substituídos por ".a", "-a" etc. Portanto, se você tiver nomes de classe com caracteres de pontuação, poderá ter problemas apenas executando uma substituição simples de regex. Aqui está um tópico do SO sobre definição de limite de palavras
Jakub P.
6
A resposta de Kabir Sarin abaixo com split ('') e indexOf é melhor IMO porque não fará com que essas classes "zumbis" com caracteres especiais apareçam.
Jakub P.
2
Esse método ainda pode ser usado com um regex melhor, como o encontrado aqui: stackoverflow.com/a/2644364/1333402
ssmith
109

Uma divisão regex no limite de palavra \bnão é a melhor solução para isso:

var prefix = "prefix";
var classes = el.className.split(" ").filter(function(c) {
    return c.lastIndexOf(prefix, 0) !== 0;
});
el.className = classes.join(" ").trim();

ou como um mixin jQuery:

$.fn.removeClassPrefix = function(prefix) {
    this.each(function(i, el) {
        var classes = el.className.split(" ").filter(function(c) {
            return c.lastIndexOf(prefix, 0) !== 0;
        });
        el.className = $.trim(classes.join(" "));
    });
    return this;
};

Atualização ES6 2018:

const prefix = "prefix";
const classes = el.className.split(" ").filter(c => !c.startsWith(prefix));
el.className = classes.join(" ").trim();
sarink
fonte
9
Esta é uma abordagem melhor do que usar RegExp com \ b (verificação de limite de palavra) porque evita que 'classes zumbis' apareçam. Se você tem classes como "prefixo-sufixo", a 'melhor resposta' neste tópico deixará a classe '-sufixo' porque \ b será dividido antes de '-' char. Sua solução de divisão-mapa-junção funciona em torno disso :) Eu criei um pequeno plugin jQuery em torno de sua solução, Kabir: ( gist.github.com/2881585 )
Jakub P.
3
+1 Eu também concordo, todas as outras respostas parecem ser apenas uma regex simples que quebraria em limites de palavra não espaciais. Se eu tiver tempo amanhã, vou fornecer um teste de unidade que prova isso.
gerges
1
Eu gosto, embora este não seja um código válido, já que a função anônima em filterdeve retornar um booleano. Isso funcionará:var classes = $(e).attr("class").split(" "); $(classes).each(function(i, item) { classes[i] = item.indexOf("prefix") === -1 ? item : "prefix-new"); }); $(e).attr("class", classes.join(" "));
Tim
Uma solução mais válida usa o mapa:$e.attr('class', $.map($e.attr('class').split(' '), function (klass) { return klass.indexOf(prefix) != 0 ? klass : undefined; }).join(' '));
M Miller
2
Essa abordagem funciona melhor. Eu usei o plugin do @JakubP. Uma sugestão se me permite: o que faz, quando agora retorna as classes, causa muito espaço. Por exemplo class="blackRow blackText orangeFace blackHead", retornará class=" orangeFace "se você executar removeClassPrefix("black");. Eu resolvi esse aparando o resultado assim: el.className = $.trim(classes.join(" "));.
Albert
29

Eu escrevi um plugin jQuery simples - alterClass , que remove a classe curinga. Opcionalmente, adicionará classes também.

$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' ) 
Pete B
fonte
Obrigado Pete! Acabei de usar seu plugin e funciona muito bem ... me economizou algum tempo!
jordan.baucke
11

Você não precisa de nenhum código específico do jQuery para lidar com isso. Basta usar um RegExp para substituí-los:

$("#a").className = $("#a").className.replace(/\bbg.*?\b/g, '');

Você pode modificar isso para suportar qualquer prefixo, mas o método mais rápido está acima, pois o RegExp será compilado apenas uma vez:

function removeClassByPrefix(el, prefix) {
    var regx = new RegExp('\\b' + prefix + '.*?\\b', 'g');
    el.className = el.className.replace(regx, '');
    return el;
}
Prestaul
fonte
9

Usando a 2ª assinatura de $.fn.removeClass:

// Considering:
var $el = $('<div class="  foo-1 a b foo-2 c foo"/>');

function makeRemoveClassHandler(regex) {
  return function (index, classes) {
    return classes.split(/\s+/).filter(function (el) {return regex.test(el);}).join(' ');
  }
}

$el.removeClass(makeRemoveClassHandler(/^foo-/));
//> [<div class=​"a b c foo">​</div>​]
abernier
fonte
Desde jQuery v1.4, esta é a melhor abordagem.
Dinei,
3

http://www.mail-archive.com/[email protected]/msg03998.html diz:

... e .removeClass () removeria todas as classes ...

Funciona para mim ;)

Felicidades


fonte
Esta é a melhor escolha! Trabalho.
Afshin Mehrabani
12
A questão não pergunta como remover todas as classes, ela pergunta como remover todas as classes que começam com uma determinada string. Essas duas coisas são muito, muito diferentes.
Chris Harrison
3

Uma abordagem que eu usaria usando construções jQuery simples e funções de manipulação de array é declarar uma função que leva id do controle e prefixo da classe e excluiu todas as classes. O código está anexado:

function removeclasses(controlIndex,classPrefix){
    var classes = $("#"+controlIndex).attr("class").split(" ");
    $.each(classes,function(index) {
        if(classes[index].indexOf(classPrefix)==0) {
            $("#"+controlIndex).removeClass(classes[index]);
        }
    });
}

Agora, esta função pode ser chamada de qualquer lugar, ao clicar no botão ou a partir do código:

removeclasses("a","bg");
nhahtdh
fonte
2

Eu estava procurando uma solução exatamente para o mesmo problema. Para remover todas as classes começando com o prefixo "fontid_" Depois de ler este artigo, escrevi um pequeno plugin que estou usando agora.

(function ($) {
        $.fn.removePrefixedClasses = function (prefix) {
            var classNames = $(this).attr('class').split(' '),
                className,
                newClassNames = [],
                i;
            //loop class names
            for(i = 0; i < classNames.length; i++) {
                className = classNames[i];
                // if prefix not found at the beggining of class name
                if(className.indexOf(prefix) !== 0) {
                    newClassNames.push(className);
                    continue;
                }
            }
            // write new list excluding filtered classNames
            $(this).attr('class', newClassNames.join(' '));
        };
    }(fQuery));

Uso:

$('#elementId').removePrefixedClasses('prefix-of-classes_');
Pawel
fonte
Isso nada mais é do que minha solução com 10x mais linhas e uma "string começa com" menos eficiente, verifique: - /
sarink
2

Para navegadores modernos:

let element = $('#a')[0];
let cls = 'bg';

element.classList.remove.apply(element.classList, Array.from(element.classList).filter(v=>v.startsWith(cls)));
Max
fonte
1

Sei que é uma pergunta antiga, mas descobri uma nova solução e quero saber se ela tem desvantagens?

$('#a')[0].className = $('#a')[0].className
                              .replace(/(^|\s)bg.*?(\s|$)/g, ' ')
                              .replace(/\s\s+/g, ' ')
                              .replace(/(^\s|\s$)/g, '');
Jan.J
fonte
1

Em uma linha ... Remove todas as classes que correspondem a uma expressão regular someRegExp

$('#my_element_id').removeClass( function() { return (this.className.match(/someRegExp/g) || []).join(' ').replace(prog.status.toLowerCase(),'');});
Adam111p
fonte
0

A resposta de Prestaul foi útil, mas não funcionou muito bem para mim. A maneira jQuery de selecionar um objeto por id não funcionou. Eu tive que usar

document.getElementById("a").className

ao invés de

$("#a").className
Brad
fonte
ou $ ("# a") [0] .className as className está disponível apenas no elemento DOM e não no objeto jQuery
Naeem Sarfraz
este é um comentário para a resposta de alguém, não uma resposta
TJ
0

Eu também uso hífen'- 'e dígitos para o nome da classe. Portanto, minha versão inclui '\ d-'

$('#a')[0].className = $('#a')[0].className.replace(/\bbg.\d-*?\b/g, '');
Jamland
fonte
0
(function($)
{
    return this.each(function()
    {
        var classes = $(this).attr('class');

        if(!classes || !regex) return false;

        var classArray = [];

        classes = classes.split(' ');

        for(var i=0, len=classes.length; i<len; i++) if(!classes[i].match(regex)) classArray.push(classes[i]);

        $(this).attr('class', classArray.join(' '));
    });
})(jQuery);
Roubar
fonte
-6
$("#element").removeAttr("class").addClass("yourClass");
majorsk8
fonte
3
Eu não acho que você leu a pergunta muito bem. O usuário não estava perguntando sobre simplesmente remover uma classe e adicionar outra.
Andrew Barber
1
@Andrew Barber: você está certo, essa não é a resposta certa, mas majorsk8 sugeriu como limpar todas as classes (removeAttr), não apenas uma;)
Inclinação