jQuery removeClass comodín

370

¿Hay alguna manera fácil de eliminar todas las clases que coinciden, por ejemplo,

color-*

entonces si tengo un elemento:

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

después de quitar, sería

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

¡Gracias!

atp
fuente
1
Una expresión regular como en la "respuesta aceptada" se romperá en los límites de palabras no espaciales. He publicado una solución alternativa a continuación. Ver también: stackoverflow.com/questions/57812/…
sarink
@KabirSarin, la respuesta aceptada se ha actualizado para solucionar esto.
Emile Bergeron
css wildcards surfingsuccess.com/css/…
Max Hodges

Respuestas:

680

La función removeClass toma un argumento de función desde jQuery 1.4 .

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

Ejemplo en vivo: http://jsfiddle.net/xa9xS/1409/

jimmystormig
fuente
44
Pensé que valía la pena señalar que esto capturará un espacio en blanco líder de clases coincidentes que no comienzan desde el principio. Javascript no es compatible con la retrospectiva positiva, por lo que tendría que usar una solución alternativa de grupo de captura. Sin embargo, es discutible, porque la función removeClass eliminará los espacios en blanco de la cadena de clase para usted a través declasses = ( value || "" ).match( rnotwhite ) || [];
eephillip
¡Me gusta más esta solución! ¿Cómo puedo verificar si se eliminan dos o más clases? es decir sport-, nav-y color-?
lowtechsun
¿Cómo harías esto para que coincida con una clase que termina *-color?
Círculo B
3
@lowtechsun puedes agregar tu expresión regular de esta manera (color-|sport-|nav-). Coincidirá color-, o sport-, o nav-. Entonces, la respuesta anterior se convertiría /(^|\s)(color-|sport-|nav-)\S+/g.
Bogie
1
La respuesta aceptada es correcta, pero idiomáticamente, usaría \ b que coincida con cualquier límite de palabra en lugar del más prolijo (^ | \ s). Entonces, por ejemplo, para eliminar todas las clases que consisten en la palabra magia seguida de un número entero no negativo y solo esas, haría coincidir en / \ bmagic \ d + \ b /.
CarlEdman
98
$('div').attr('class', function(i, c){
    return c.replace(/(^|\s)color-\S+/g, '');
});
Kobi
fuente
55
Me gusta esto, ya que reduce la sobrecarga y va directo al grano. ¿Por qué usar remove class cuando attr hace el trabajo mejor?
Angry Dan
2
creo que necesitas protegerte contra clases vacías ( c is undefined)? Al menos cuando lo probé a continuación en mi plugin en esta página, $('a').stripClass('post', 1)arrojé "TypeError: No se puede llamar al método 'reemplazar' de indefinido"
drzaus
1
@Kobi, sí, no creo que sea posible filtrar un atributo y devolver un resultado que no lo tiene, $('div[class]')solo debería devolver elementos con class, tengan o no un valor. escenarios de prueba: jsfiddle.net/drzaus/m83mv
drzaus
1
@ Kobi - Creo que veo a lo que te refieres; en los casos extremos como .removeProp('class')o .className=undefinedel filtro [class]todavía devuelve algo, son justos undefined. Por lo tanto, técnicamente todavía tiene una clase (a diferencia de .removeAttr('class'), por eso rompe su función pero no mi variante. Jsfiddle.net/drzaus/m83mv/4
drzaus
1
Agregar una prueba rápida funciona para mí:return c && c.replace(/\bcolor-\S+/g, '');
ssmith
50

He escrito un complemento que hace esto llamado alterClass - Eliminar clases de elementos con coincidencia de comodines. Opcionalmente agregue clases: https://gist.github.com/1517285

$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
Pete B
fuente
1
Muy agradable de hecho ... me ayudó a reutilizar algún código donde solo necesitaba eliminar Twitter Boostrapclases como esta:$(".search div").children('div').alterClass('span* row-fluid');
Leniel Maccaferri
15

He generalizado esto en un complemento de Jquery que toma una expresión 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(' ');
  });
};

Entonces, para este caso, el uso sería (tanto Coffee como Javascript):

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

Tenga en cuenta que estoy usando la Array.filterfunción que no existe en IE <9. En su lugar, puede usar la función de filtro de Underscore o Google para un polyfill como este WTFPL .

tembloroso
fuente
11

Si desea usarlo en otros lugares, le sugiero una extensión. Este está funcionando bien para mí.

 $.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
fuente
4

podemos obtener todas las clases por .attr("class"), y a Array, Y 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]);
    }
}

demostración: http://jsfiddle.net/L2A27/1/

meni181818
fuente
Agregado var prefix='color';y cambiado ...if (classArr[i].substr(0, prefix.length) != prefix)
Rich C
4

Similar a la respuesta de @ tremby , aquí está la respuesta de @ Kobi como un complemento que coincidirá con prefijos o sufijos.

  • ex) tiras btn-miniy btn-dangerno btncuando stripClass("btn-").
  • ex) tiras horsebtny cowbtnpero no btn-minio btncuandostripClass('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
fuente
1
Para el registro, no estoy de acuerdo con que esto sea más simple.
temblor
@tremby lo siento, quise decir más simple en el uso típico (es decir, prefijos y sufijos), ya que no tiene que escribir una expresión regular cada vez
drzaus
3
Todavía no estoy de acuerdo. Con su método, debe leer la documentación y recordar cuál endOrBegindebe ser exactamente el valor . No se explica por sí mismo. ¿Qué tiene de difícil escribir una expresión regular? /^match-at-start/y /match-at-end$/son conocidos por todos los desarrolladores de JS. Pero cada uno a lo suyo.
temblor
1
@tremby aparte de expresiones regulares que piden para ser objeto de abuso, una opción no expresiones regulares es más compatible con la firma existente addClass, removeClassy toggleClass, que se sabe que todos los desarrolladores de jQuery. ¿Qué tiene de difícil leer la documentación? ;)
drzaus
2
No hay nada difícil en leer la documentación, pero como dice @tremby, su solución se explica por sí misma, mientras que la suya requiere documentación. Las soluciones autoexplicativas son más simples de usar por definición.
Francisco Hodge
2

Para un complemento jQuery intente esto

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

o esto

$.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
fuente
2

Basado en la respuesta de ARS81 (que solo coincide con los nombres de clase que comienzan con), aquí hay una versión más flexible. También una versión regex.hasClass()

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
fuente
2

Esto eliminará efectivamente todos los nombres de clase que comienzan con prefixel classatributo de un nodo . Otras respuestas no admiten elementos SVG (al momento de escribir esto), pero esta solución sí:

$.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
fuente
¿No sería más eficiente crear el RegExpobjeto una vez, fuera de cada devolución de llamada?
Emile Bergeron
1
@EmileBergeron: ¡sí lo sería! Haré cambios
vsync
2

Tuve el mismo problema y se me ocurrió lo siguiente que utiliza el método _.filter de subrayado. Una vez que descubrí que removeClass toma una función y le proporciona una lista de nombres de clase, fue fácil convertir eso en una matriz y filtrar el nombre de clase para volver al 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
fuente
1
¿Puede explicar lo que hace el guión bajo en _.filter
bart
2

También puede hacer esto con JavaScript vainilla usando Element.classList . Tampoco es necesario usar una expresión regular:

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

Nota: Tenga en cuenta que creamos una Arraycopia del classListantes de comenzar, eso es importante ya que classListes un live DomTokenListque se actualizará cuando se eliminen las clases.

kzar
fuente
1

También puede usar la classNamepropiedad del objeto DOM del elemento:

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

Una función genérica que elimina cualquier clase que comience con 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
fuente
0

Una división de expresiones regulares en el límite de palabras \bno es la mejor solución para esto:

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

o como jQuery mixin:

$.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
fuente
0

si tiene más de un elemento que tiene un nombre de clase 'ejemplo', para eliminar clases de 'color-' en todos ellos puede hacer esto: [usando jquery]

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

si no pone [a-z1-9 -] * en su expresión regular, no eliminará las clases que tienen un número o algunos '-' en sus nombres.

mohammad eslahi sani
fuente
0

Si solo necesita eliminar el último color establecido, lo siguiente puede ser adecuado para usted.

En mi situación, necesitaba agregar una clase de color a la etiqueta del cuerpo en un evento de clic y eliminar el último color establecido. En ese caso, almacena el color actual y luego busca la etiqueta de datos para eliminar el último color establecido.

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

Puede que no sea exactamente lo que necesita, pero para mí fue y esta fue la primera pregunta SO que miré, por lo que pensé en compartir mi solución en caso de que ayude a alguien.

redfox05
fuente
Eso es irrelevante aquí. Podría haber respondido su propia pregunta, ya que es un comportamiento alentado en SO.
Emile Bergeron
@Emile: Eso es cierto. Podría hacerlo, ya que no responde directamente a la pregunta original. ¿Debo dejar esta respuesta o eliminarla?
redfox05
En ese momento, es bajo su propio riesgo, aún no se ha votado ni votado negativamente. Para que pueda pasar a su propia pregunta sin riesgo. Además, trate de evitar duplicados verificando si ya hay una pregunta sobre esto.
Emile Bergeron
0

Una forma alternativa de abordar este problema es utilizar atributos de datos, que por naturaleza son únicos.

Establecería el color de un elemento como: $el.attr('data-color', 'red');

Y lo diseñarías en CSS como: [data-color="red"]{ color: tomato; }

Esto niega la necesidad de usar clases, lo que tiene el efecto secundario de tener que eliminar las clases antiguas.

rorymorris89
fuente