jQuery removeClass joker

371

Existe-t-il un moyen simple de supprimer toutes les classes correspondantes, par exemple,

color-*

donc si j'ai un élément:

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

après le retrait, il serait

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

Merci!

atp
la source
1
Un regex comme dans la "réponse acceptée" se brisera sur les limites des mots non spatiaux. J'ai posté une solution alternative ci-dessous. Voir aussi: stackoverflow.com/questions/57812/…
sarink
@KabirSarin, la réponse acceptée a depuis été mise à jour pour résoudre ce problème.
Emile Bergeron
css wildcards surfingsuccess.com/css/…
Max Hodges

Réponses:

680

La fonction removeClass prend un argument de fonction depuis jQuery 1.4 .

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

Exemple en direct: http://jsfiddle.net/xa9xS/1409/

jimmystormig
la source
4
J'ai pensé qu'il valait la peine de noter que cela capturera un espace blanc de premier plan de classes correspondantes qui ne commencent pas au début. Javascript ne prend pas en charge le lookbehind positif, vous devrez donc utiliser une solution de contournement du groupe de capture. Cependant, c'est un sujet discutable, car la fonction removeClass supprimera les espaces blancs de votre chaîne de classe pour vous viaclasses = ( value || "" ).match( rnotwhite ) || [];
eephillip
Je préfère cette solution! Comment puis-je vérifier la suppression de deux classes ou plus? c'est à dire sport-, nav-et color-?
lowtechsun
Comment feriez-vous cela pour correspondre à une fin de classe comme *-color?
Circle B
3
@lowtechsun, vous pouvez ajouter votre regex comme ceci (color-|sport-|nav-). Il correspondra color-, ou sport-, ou nav-. Ainsi, la réponse ci-dessus deviendrait /(^|\s)(color-|sport-|nav-)\S+/g.
Bogie
1
La réponse acceptée est correcte, mais idiomatiquement, j'utiliserais \ b qui correspond à n'importe quelle limite de mot plutôt que le plus verbeux (^ | \ s). Ainsi, par exemple, pour supprimer toutes les classes constituées du mot magie suivi d'un entier non négatif et uniquement celles-ci, je ferais correspondre sur / \ bmagic \ d + \ b /.
CarlEdman
98
$('div').attr('class', function(i, c){
    return c.replace(/(^|\s)color-\S+/g, '');
});
Kobi
la source
5
J'aime cela car il réduit les frais généraux et va droit au but. Pourquoi utiliser remove class lorsque attr fait le travail mieux?
Angry Dan
2
Je pense que vous devez vous protéger contre les classes vides ( c is undefined)? Au moins quand je l'ai essayé ci- dessous dans mon plugin sur cette page, $('a').stripClass('post', 1)j'ai lancé "TypeError: Impossible d'appeler la méthode 'replace' of undefined"
drzaus
1
@Kobi ouais je ne pense pas qu'il soit possible de filtrer sur un attribut et de renvoyer un résultat qui ne l'a pas - $('div[class]')devrait seulement renvoyer des éléments avec class, qu'ils aient une valeur ou non. scénarios de test: jsfiddle.net/drzaus/m83mv
drzaus
1
@Kobi - Je pense que je vois où vous voulez en venir; dans les cas de bord comme .removeProp('class')ou .className=undefinedle filtre [class]renvoie toujours quelque chose, ils sont juste undefined. Donc techniquement, il a toujours une classe (par opposition à .removeAttr('class'), c'est pourquoi il casse votre fonction mais pas ma variante. Jsfiddle.net/drzaus/m83mv/4
drzaus
1
L'ajout d'un test rapide fonctionne pour moi:return c && c.replace(/\bcolor-\S+/g, '');
ssmith
50

J'ai écrit un plugin qui fait cela appelé alterClass - Supprimer les classes d'éléments avec une correspondance générique. Ajoutez éventuellement des classes: https://gist.github.com/1517285

$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
Pete B
la source
1
Très bien en effet ... m'a aidé à réutiliser du code où j'avais juste besoin de supprimer des Twitter Boostrapclasses comme celle-ci:$(".search div").children('div').alterClass('span* row-fluid');
Leniel Maccaferri
15

J'ai généralisé cela dans un plugin Jquery qui prend un regex comme argument.

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

Donc, dans ce cas, l'utilisation serait (à la fois Coffee et Javascript):

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

Notez que j'utilise la Array.filterfonction qui n'existe pas dans IE <9. Vous pouvez utiliser la fonction de filtre Underscore à la place ou Google pour un polyfill comme celui-ci WTFPL .

tremby
la source
11

Si vous souhaitez l'utiliser dans d'autres endroits, je vous suggère une extension. Celui-ci fonctionne bien pour moi.

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

Usage:

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

nous pouvons obtenir toutes les classes par .attr("class")et vers 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]);
    }
}

démo: http://jsfiddle.net/L2A27/1/

meni181818
la source
Ajouté var prefix='color';et modifié ...if (classArr[i].substr(0, prefix.length) != prefix)
Rich C
4

Semblables à @ tremby réponse , voici @ Kobi réponse en tant que plug - in qui correspondent soit des préfixes ou suffixes.

  • ex) bandes btn-miniet btn-dangermais pas btnquand stripClass("btn-").
  • ex) bandes horsebtnet cowbtnmais pas btn-miniou btnquandstripClass('btn', 1)

Code:

$.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
la source
1
Pour mémoire, je ne suis pas d'accord pour dire que c'est plus simple.
tremby
@tremby désolé, je voulais dire plus simple dans une utilisation typique (c'est-à-dire des préfixes et des suffixes), car vous n'avez pas à écrire une expression
régulière à
3
Je suis toujours en désaccord. Avec votre méthode, vous devez lire la documentation et vous rappeler quelle endOrBegindoit être exactement la valeur . Ce n'est pas explicite. Qu'est-ce qui est difficile à écrire une expression régulière? /^match-at-start/et /match-at-end$/sont connus de tous les développeurs JS. Mais chacun à sa façon.
tremby
1
@tremby autre que regexes mendient à abuser, une option non plus regex correspond étroitement à la signature existante de addClass, removeClasset toggleClassqui est connu pour chaque développeur jQuery. Qu'est-ce qui est difficile à lire dans la documentation? ;)
drzaus
2
Il n'y a rien de difficile à lire la documentation, mais comme le dit @tremby, sa solution est explicite, tandis que la vôtre nécessite de la documentation. Les solutions auto-explicatives sont plus simples à utiliser par définition.
Francisco Hodge
2

Pour un plugin jQuery essayez ceci

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

ou ca

$.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
la source
2

Basé sur la réponse d' ARS81 (qui ne correspond qu'aux noms de classe commençant par), voici une version plus flexible. Aussi une version regex.hasClass()

Usage: $('.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
la source
2

Cela supprimera efficacement tous les noms de classe qui commencent par prefixl' classattribut d'un nœud . D'autres réponses ne prennent pas en charge les éléments SVG (au moment d'écrire ceci), mais cette solution:

$.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
la source
Ne serait-il pas plus efficace de créer l' RegExpobjet une fois, à partir de chaque rappel?
Emile Bergeron
1
@EmileBergeron - oui ce serait! Je ferai des changements
vsync
2

J'ai eu le même problème et j'ai trouvé ce qui suit qui utilise la méthode _.filter du soulignement. Une fois que j'ai découvert que removeClass prend une fonction et vous fournit une liste de noms de classe, il était facile de transformer cela en un tableau et de filtrer le nom de classe pour revenir à la méthode 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;
});
nynynie
la source
1
Pouvez-vous expliquer ce que le trait de soulignement fait dans _.filter
bart
2

Vous pouvez également le faire avec JavaScript vanilla en utilisant Element.classList . Pas besoin non plus d'utiliser une expression régulière:

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

Remarque: notez que nous créons une Arraycopie du classListavant de commencer, c'est important car classListc'est un live DomTokenListqui se mettra à jour lorsque les classes seront supprimées.

kzar
la source
J'aime cette méthode, mais existe-t-il un moyen de rendre cette fonction plus globale? Par exemple; Pour donner un paramètre à fonctionner avec le nom de classe que vous souhaitez supprimer? Je pense que ce serait encore mieux :)
Loosie94 Il y a
2

Une fonction générique qui supprime toute classe commençant par 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
la source
1

Vous pouvez également utiliser la classNamepropriété de l'objet DOM de l'élément:

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

Un regex se divisant sur la frontière de mot \bn'est pas la meilleure solution pour cela:

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

ou en mixage 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
la source
0

si vous avez plusieurs éléments ayant un nom de classe 'exemple', pour supprimer les classes de 'couleur-' dans chacun d'eux, vous pouvez le faire: [en utilisant 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 vous ne mettez pas [a-z1-9 -] * dans votre regex, cela ne supprimera pas les classes qui ont un nombre ou des '-' dans leurs noms.

mohammad eslahi sani
la source
0

Si vous avez juste besoin de supprimer la dernière couleur définie, les éléments suivants peuvent vous convenir.

Dans ma situation, je devais ajouter une classe de couleurs à la balise body sur un événement de clic et supprimer la dernière couleur définie. Dans ce cas, vous stockez la couleur actuelle, puis recherchez la balise de données pour supprimer la dernière couleur définie.

Code:

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

Ce n'est peut-être pas exactement ce dont vous avez besoin, mais pour moi, c'était le cas et c'était la première question SO que j'ai examinée, alors j'ai pensé partager ma solution au cas où cela aiderait quelqu'un.

redfox05
la source
Ce n'est pas pertinent ici. Vous auriez pu répondre à votre propre question car il s'agit d'un comportement encouragé sur SO.
Emile Bergeron
@Emile: C'est vrai. Je pourrais le faire car il ne répond pas directement à la question d'origine. Dois-je laisser cette réponse ou la supprimer?
redfox05
À ce stade, c'est à vos risques et périls, il n'a pas encore été voté ni voté. Vous pouvez donc le déplacer sans risque vers votre propre question. Essayez également d'éviter les doublons en vérifiant s'il y a déjà une question à ce sujet.
Emile Bergeron
0

Une autre façon d'aborder ce problème consiste à utiliser des attributs de données, qui sont par nature uniques.

Vous définiriez la couleur d'un élément comme: $el.attr('data-color', 'red');

Et vous le styleriez en CSS comme: [data-color="red"]{ color: tomato; }

Cela annule la nécessité d'utiliser des classes, ce qui a pour effet secondaire de devoir supprimer les anciennes classes.

rorymorris89
la source