curinga jQuery removeClass

370

Existe alguma maneira fácil de remover todas as classes correspondentes, por exemplo,

color-*

então se eu tiver um elemento:

<div id="hello" class="color-red color-brown foo bar"></div>

após a remoção, seria

<div id="hello" class="foo bar"></div>

Obrigado!

atp
fonte
11
Uma regex como na "resposta aceita" será quebrada nos limites de palavras que não são espaços. Publiquei uma solução alternativa abaixo. Consulte também: stackoverflow.com/questions/57812/…
sarink
@KabirSarin, a resposta aceita foi atualizada para corrigir isso.
Emile Bergeron
css wildcards surfingsuccess.com/css/...
Max Hodges

Respostas:

679

A função removeClass usa um argumento de função desde o jQuery 1.4 .

$("#hello").removeClass (function (index, className) {
    return (className.match (/(^|\s)color-\S+/g) || []).join(' ');
});

Exemplo ao vivo: http://jsfiddle.net/xa9xS/1409/

jimmystormig
fonte
4
Eu pensei que vale a pena notar que isso irá capturar um espaço em branco líder de classes correspondentes que não começam no início. O Javascript não oferece suporte positivo, portanto você teria que usar uma solução alternativa para o grupo de captura. No entanto, é discutível, porque a função removeClass retira o espaço em branco da string de classe para você viaclasses = ( value || "" ).match( rnotwhite ) || [];
eephillip
Eu gosto mais desta solução! Como posso verificar se duas ou mais classes serão removidas? ou seja sport-, nav-e color-?
lowtechsun
Como você faria isso para combinar com um final de classe como *-color?
Circle B
3
@lowtechsun, você pode adicionar seu regex assim (color-|sport-|nav-). Combina color-, ou sport-, ou nav-. Então, a resposta acima se tornaria /(^|\s)(color-|sport-|nav-)\S+/g.
Bogie
11
A resposta aceita está correta, mas, em termos linguísticos, eu usaria \ b, que corresponde a qualquer limite de palavras, e não ao mais prolixo (^ | \ s). Assim, por exemplo, para remover todas as classes que consistem na palavra mágica, seguidas por um número inteiro não negativo e somente aquelas, eu corresponderia em / \ bmagic \ d + \ b /.
CarlEdman
98
$('div').attr('class', function(i, c){
    return c.replace(/(^|\s)color-\S+/g, '');
});
Kobi
fonte
5
Eu gosto disso, pois reduz a sobrecarga e vai direto ao ponto. Por que usar remove class quando attr faz o trabalho melhor?
Angry Dan
2
Eu acho que você precisa se proteger contra classes vazias ( c is undefined)? Pelo menos quando eu tentei seguir no meu plugin nesta página, $('a').stripClass('post', 1)jogou "TypeError: Não é possível chamar o método 'substituir' de indefinido"
drzaus
11
@ Kobi Sim, eu não acho que é possível filtrar um atributo e retornar um resultado que não o possui - $('div[class]')só deve retornar elementos com class, se eles têm um valor ou não. testando cenários: jsfiddle.net/drzaus/m83mv
drzaus
11
@Kobi - Acho que vejo o que você está recebendo; nos casos extremos como .removeProp('class')ou .className=undefinedo filtro [class]ainda retorna algo, eles são justos undefined. Então, tecnicamente ele ainda tem uma classe (em oposição a .removeAttr('class'), razão pela qual ele quebra sua função, mas não a minha variante. Jsfiddle.net/drzaus/m83mv/4
drzaus
11
A adição de um teste rápido funciona para mim:return c && c.replace(/\bcolor-\S+/g, '');
ssmith
50

Eu escrevi um plugin que faz isso chamado alterClass - Remove classes de elemento com correspondência de curinga. Opcionalmente, adicione classes: https://gist.github.com/1517285

$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
Pete B
fonte
11
Muito bom de facto ... me ajudou a reutilizar algum código onde eu só precisava para remover Twitter Boostrapas classes como este:$(".search div").children('div').alterClass('span* row-fluid');
Leniel Maccaferri
15

Eu generalizei isso em um plugin Jquery que usa uma expressão regular como argumento.

Café:

$.fn.removeClassRegex = (regex) ->
  $(@).removeClass (index, classes) ->
    classes.split(/\s+/).filter (c) ->
      regex.test c
    .join ' '

Javascript:

$.fn.removeClassRegex = function(regex) {
  return $(this).removeClass(function(index, classes) {
    return classes.split(/\s+/).filter(function(c) {
      return regex.test(c);
    }).join(' ');
  });
};

Portanto, nesse caso, o uso seria (Coffee e Javascript):

$('#hello').removeClassRegex(/^color-/)

Observe que estou usando a Array.filterfunção que não existe no IE <9. Você poderia usar a função de filtro do Underscore ou o Google para um polyfill como este WTFPL .

tremer
fonte
11

Se você quiser usá-lo em outros lugares, sugiro uma extensão. Este está funcionando bem para mim.

 $.fn.removeClassStartingWith = function (filter) {
    $(this).removeClass(function (index, className) {
        return (className.match(new RegExp("\\S*" + filter + "\\S*", 'g')) || []).join(' ')
    });
    return this;
};

Uso:

$(".myClass").removeClassStartingWith('color');
Charly Guirao
fonte
4

podemos obter todas as classes por .attr("class"), e para Array, And loop & filter:

var classArr = $("#sample").attr("class").split(" ")
$("#sample").attr("class", "")
for(var i = 0; i < classArr.length; i ++) {
    // some condition/filter
    if(classArr[i].substr(0, 5) != "color") {
        $("#sample").addClass(classArr[i]);
    }
}

demo: http://jsfiddle.net/L2A27/1/

meni181818
fonte
Adicionado var prefix='color';e alterado ...if (classArr[i].substr(0, prefix.length) != prefix)
Rich C
4

Semelhante à resposta de @ tremby , aqui está a resposta de @ Kobi como um plug-in que corresponderá a prefixos ou sufixos.

  • ex) tiras btn-minie btn-dangermas não btnquando stripClass("btn-").
  • ex) tiras horsebtne cowbtnmas não btn-miniou btnquandostripClass('btn', 1)

Código:

$.fn.stripClass = function (partialMatch, endOrBegin) {
    /// <summary>
    /// The way removeClass should have been implemented -- accepts a partialMatch (like "btn-") to search on and remove
    /// </summary>
    /// <param name="partialMatch">the class partial to match against, like "btn-" to match "btn-danger btn-active" but not "btn"</param>
    /// <param name="endOrBegin">omit for beginning match; provide a 'truthy' value to only find classes ending with match</param>
    /// <returns type=""></returns>
    var x = new RegExp((!endOrBegin ? "\\b" : "\\S+") + partialMatch + "\\S*", 'g');

    // https://stackoverflow.com/a/2644364/1037948
    this.attr('class', function (i, c) {
        if (!c) return; // protect against no class
        return c.replace(x, '');
    });
    return this;
};

https://gist.github.com/zaus/6734731

drzaus
fonte
11
Para constar, discordo que isso é mais simples.
tremby 30/07
@tremby desculpe, eu quis dizer mais simples em típico de uso (ou seja, prefixos e sufixos), desde que você não tem que escrever um regex de cada vez
drzaus
3
Eu ainda discordo. Com o seu método, você deve ler a documentação e lembrar qual endOrBegindeve ser exatamente o valor . Não é auto-explicativo. O que é difícil escrever um regex? /^match-at-start/e /match-at-end$/são conhecidos por todo desenvolvedor JS. Mas cada um por conta própria.
21814 tremby
11
@tremby diferente de expressões regulares implorando para ser abusado, uma opção não-regex corresponda melhor a assinatura existente addClass, removeClasse toggleClass, o que é conhecido por todos os desenvolvedores jQuery. O que é difícil de ler na documentação? ;)
drzaus
2
Não é difícil ler a documentação, mas como o @tremby diz, a solução dele é auto-explicativa, enquanto a sua requer documentação. Soluções auto-explicativas são mais simples de usar por definição.
Francisco Hodge
2

Para um plugin jQuery, tente este

$.fn.removeClassLike = function(name) {
    return this.removeClass(function(index, css) {
        return (css.match(new RegExp('\\b(' + name + '\\S*)\\b', 'g')) || []).join(' ');
    });
};

ou isto

$.fn.removeClassLike = function(name) {
    var classes = this.attr('class');
    if (classes) {
        classes = classes.replace(new RegExp('\\b' + name + '\\S*\\s?', 'g'), '').trim();
        classes ? this.attr('class', classes) : this.removeAttr('class');
    }
    return this;
};
ARS81
fonte
2

Baseado em ARS81 's resposta (que corresponde apenas nomes de classe começando com), aqui está uma versão mais flexível. Também uma hasClass()versão regex.

Uso: $('.selector').removeClassRegex('\\S*-foo[0-9]+')

$.fn.removeClassRegex = function(name) {
  return this.removeClass(function(index, css) {
    return (css.match(new RegExp('\\b(' + name + ')\\b', 'g')) || []).join(' ');
  });
};

$.fn.hasClassRegex = function(name) {
  return this.attr('class').match(new RegExp('\\b(' + name + ')\\b', 'g')) !== null;
};
Pascal Polleunus
fonte
2

Isso removerá efetivamente todos os nomes de classe que começam com prefixo classatributo de um nó . Outras respostas não suportam elementos SVG (no momento em que escrevemos isso), mas esta solução:

$.fn.removeClassPrefix = function(prefix){
    var c, regex = new RegExp("(^|\\s)" + prefix + "\\S+", 'g');
    return this.each(function(){
        c = this.getAttribute('class');
        this.setAttribute('class', c.replace(regex, ''));
    });
};
vsync
fonte
Não seria mais eficiente criar o RegExpobjeto uma vez, a partir de cada retorno de chamada?
Emile Bergeron
11
@EmileBergeron - sim, seria! Vou fazer alterações
vsync
2

Eu tive o mesmo problema e criei o seguinte que usa o método _.filter do sublinhado. Depois que descobri que removeClass usa uma função e fornece uma lista de nomes de classe, foi fácil transformá-lo em uma matriz e filtrar o nome da classe para retornar ao método removeClass.

// Wildcard removeClass on 'color-*'
$('[class^="color-"]').removeClass (function (index, classes) {
  var
    classesArray = classes.split(' '),
    removeClass = _.filter(classesArray, function(className){ return className.indexOf('color-') === 0; }).toString();

  return removeClass;
});
nynyny
fonte
11
Pode explicar o que o sublinhado faz em _.filter
Bart
2

Você também pode fazer isso com JavaScript vanilla usando Element.classList . Também não é necessário usar uma expressão regular:

function removeColorClasses(element) { for (let className of Array.from(element.classList)) if (className.startsWith("color-")) element.classList.remove(className); }

Nota: Observe que criamos uma Arraycópia do classListantes de iniciar, o que é importante, pois classListé um live DomTokenListque será atualizado à medida que as classes forem removidas.

kzar
fonte
1

Você também pode usar a classNamepropriedade do objeto DOM do elemento:

var $hello = $('#hello');
$('#hello').attr('class', $hello.get(0).className.replace(/\bcolor-\S+/g, ''));
Alexander Wallin
fonte
1

Uma função genérica que remove qualquer classe que comece com begin:

function removeClassStartingWith(node, begin) {
    node.removeClass (function (index, className) {
        return (className.match ( new RegExp("\\b"+begin+"\\S+", "g") ) || []).join(' ');
    });
}

http://jsfiddle.net/xa9xS/2900/

var begin = 'color-';

function removeClassStartingWith(node, begin) {
    node.removeClass (function (index, className) {
        return (className.match ( new RegExp("\\b"+begin+"\\S+", "g") ) || []).join(' ');
    });
}

removeClassStartingWith($('#hello'), 'color-');

console.log($("#hello")[0].className);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="hello" class="color-red color-brown foo bar"></div>

Fifi
fonte
0

Uma regex dividida no limite da 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(" ");

ou como um mix 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 = classes.join(" ");
    });
    return this;
};
sarink
fonte
0

se você tiver mais de um elemento com um nome de classe 'exemplo', para remover classes de 'cor-' em todas elas, você pode fazer isso: [using jquery]

var objs = $('html').find('.example');
for(index=0 ; index < obj1s.length ; index++){
    objs[index].className = objs[index].className.replace(/col-[a-z1-9\-]*/,'');
}

se você não colocar [a-z1-9 -] * no seu regex, não removerá as classes que têm um número ou algum '-' em seus nomes.

mohammad eslahi sani
fonte
0

Se você apenas precisar remover a última cor definida, o seguinte poderá lhe agradar.

Na minha situação, eu precisava adicionar uma classe de cores à tag body em um evento de clique e remover a última cor definida. Nesse caso, você armazena a cor atual e procura a etiqueta de dados para remover a última cor definida.

Código:

var colorID = 'Whatever your new color is';

var bodyTag = $('body');
var prevColor = bodyTag.data('currentColor'); // get current color
bodyTag.removeClass(prevColor);
bodyTag.addClass(colorID);
bodyTag.data('currentColor',colorID); // set the new color as current

Pode não ser exatamente o que você precisa, mas para mim foi e essa foi a primeira pergunta do SO que eu olhei, então pensei em compartilhar minha solução caso isso ajude alguém.

redfox05
fonte
Isso é irrelevante aqui. Você poderia ter respondido sua própria pergunta, pois é um comportamento incentivado no SO.
Emile Bergeron
@Emile: Isso é verdade. Eu poderia fazer isso, pois não está respondendo diretamente à pergunta original. Devo deixar essa resposta ou removê-la?
precisa saber é o seguinte
Nesse ponto, é por seu próprio risco, não foi votado nem votado ainda. Então você pode passar para sua própria pergunta sem risco. Além disso, tente evitar duplicatas verificando se já existe uma pergunta sobre isso.
Emile Bergeron
0

Uma maneira alternativa de abordar esse problema é usar atributos de dados, que são por natureza exclusivos.

Você definiria a cor de um elemento como: $el.attr('data-color', 'red');

E você o estilizaria em css como: [data-color="red"]{ color: tomato; }

Isso nega a necessidade de usar classes, que tem o efeito colateral de precisar remover classes antigas.

rorymorris89
fonte