jQuery removeClass wildcard

370

Czy jest jakiś prosty sposób na usunięcie wszystkich pasujących klas, na przykład

color-*

więc jeśli mam element:

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

po usunięciu byłoby

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

Dzięki!

atp
źródło
1
Wyrażenie regularne, takie jak w „akceptowanej odpowiedzi”, złamie się na nieprzestrzennych granicach słów. Poniżej zamieściłem alternatywne rozwiązanie. Zobacz także: stackoverflow.com/questions/57812/…
sarink
@KabirSarin zaakceptowana odpowiedź została zaktualizowana, aby to naprawić.
Emile Bergeron,
css wildcards surfingsuccess.com/css/…
Max Hodges

Odpowiedzi:

679

Funkcja removeClass pobiera argument funkcji od jQuery 1.4 .

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

Przykład na żywo: http://jsfiddle.net/xa9xS/1409/

jimmystormig
źródło
4
Pomyślałem, że warto zauważyć, że przechwyci to wiodącą białą grupę dopasowanych klas, które nie zaczynają się od początku. JavaScript nie obsługuje pozytywnego wyglądu, więc musisz użyć obejścia grupy przechwytywania. Jest to jednak kwestia dyskusyjna, ponieważ funkcja removeClass usunie dla ciebie białe znaki z ciągu klasyclasses = ( value || "" ).match( rnotwhite ) || [];
eephillip
Najbardziej podoba mi się to rozwiązanie! Jak mogę sprawdzić, czy dwie lub więcej klas ma zostać usuniętych? to znaczy sport-, nav-i color-?
lowtechsun
Jak zrobiłbyś to, aby dopasować się do klasy kończącej się jak *-color?
Okrąg B
3
@lowtechsun możesz dodać w wyrażeniu regularnym w ten sposób (color-|sport-|nav-). Będzie pasować color-, lub sport-, lub nav-. Tak więc powyższa odpowiedź stałaby się /(^|\s)(color-|sport-|nav-)\S+/g.
Bogie,
1
Przyjęta odpowiedź jest poprawna, ale idiomatycznie użyłbym \ b, który pasuje do dowolnej granicy słów, a nie do bardziej nieporadnych (^ | \ s). Na przykład, aby usunąć wszystkie klasy składające się ze słowa magia, po której następuje nieujemna liczba całkowita i tylko te, dopasowałbym na / \ bmagic \ d + \ b /.
CarlEdman,
98
$('div').attr('class', function(i, c){
    return c.replace(/(^|\s)color-\S+/g, '');
});
Kobi
źródło
5
Podoba mi się to, ponieważ zmniejsza obciążenie i przechodzi od razu do rzeczy. Po co używać klasy usuń, gdy attr wykonuje zadanie lepiej?
Angry Dan
2
myślę, że musisz chronić się przed pustymi klasami ( c is undefined)? Przynajmniej kiedy wypróbowałem to poniżej w mojej wtyczce na tej stronie, $('a').stripClass('post', 1)rzuciłem „TypeError: Nie można nazwać metody„ replace ”niezdefiniowanej”
drzaus
1
@Kobi tak, nie sądzę, że można filtrować atrybut i zwracać wynik, który go nie ma - $('div[class]')powinien zwracać tylko elementy class, niezależnie od tego, czy mają wartość, czy nie. scenariusze testowe: jsfiddle.net/drzaus/m83mv
drzaus
1
@Kobi - Myślę, że rozumiem, o co ci chodzi; w skrajnych przypadkach jak .removeProp('class')lub .className=undefinedfiltr [class]wciąż coś zwraca, są po prostu undefined. Więc technicznie nadal ma klasę (w przeciwieństwie do .removeAttr('class'), dlatego psuje twoją funkcję, ale nie mój wariant. Jsfiddle.net/drzaus/m83mv/4
drzaus
1
Dodanie szybkiego testu działa dla mnie:return c && c.replace(/\bcolor-\S+/g, '');
ssmith
50

Napisałem wtyczkę, która robi to o nazwie alterClass - Usuń klasy elementów z dopasowaniem symboli wieloznacznych. Opcjonalnie dodaj klasy: https://gist.github.com/1517285

$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
Pete B.
źródło
1
Naprawdę bardzo miło ... pomógł mi ponownie użyć kodu, w którym musiałem tylko usunąć Twitter Boostraptakie klasy:$(".search div").children('div').alterClass('span* row-fluid');
Leniel Maccaferri
15

Uogólniłem to na wtyczkę Jquery, która przyjmuje wyrażenie jako argument.

Kawa:

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

Tak więc w tym przypadku użycie byłoby (zarówno Kawa, jak i JavaScript):

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

Zauważ, że używam Array.filterfunkcji, która nie istnieje w IE <9. Możesz użyć funkcji filtru podkreślenia zamiast Google lub Google do wypełnienia takiego jak ten WTFPL .

drżenie
źródło
11

Jeśli chcesz go używać w innych miejscach, sugeruję rozszerzenie. Ten działa dla mnie dobrze.

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

Stosowanie:

$(".myClass").removeClassStartingWith('color');
Charly Guirao
źródło
4

możemy pobrać wszystkie klasy .attr("class"), i do tablicy, i zapętlić i filtrować:

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
źródło
Dodano var prefix='color';i zmieniono ...if (classArr[i].substr(0, prefix.length) != prefix)
Rich C
4

Podobny do użytkownika @ tremby odpowiedź , oto @ Kobi za odpowiedź jako plugin, który będzie pasował zarówno przedrostków lub przyrostków.

  • np. paski btn-minii btn-dangerale nie btnkiedy stripClass("btn-").
  • np. paski horsebtni cowbtnale nie btn-minilub btnkiedystripClass('btn', 1)

Kod:

$.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
źródło
1
Dla przypomnienia, nie zgadzam się, że jest to prostsze.
tremby
@tremby przepraszam, miałem na myśli prostsze w typowym użyciu (tj. przedrostki i przyrostki), ponieważ nie trzeba za każdym razem pisać wyrażenia regularnego
drzaus
3
Nadal się nie zgadzam. Swoją metodą musisz przeczytać dokumentację i pamiętać, jaką dokładnie endOrBeginpowinna być wartość. To nie jest oczywiste. Co jest trudnego w napisaniu wyrażenia regularnego? /^match-at-start/i /match-at-end$/są znane wszystkim programistom JS. Ale każdy na swój.
tremby
1
@tremby inny niż Wyrażenia regularne żebranie być nadużywane, opcja non-regex bardziej zbliżony do istniejącego podpisu addClass, removeClassi toggleClass, który jest znany każdemu jQuery dewelopera. Co jest trudne w czytaniu dokumentacji? ;)
drzaus
2
Nie ma nic trudnego w czytaniu dokumentacji, ale jak mówi @tremby, jego rozwiązanie jest oczywiste, podczas gdy twoje wymaga dokumentacji. Z oczywistych względów prostsze w użyciu są rozwiązania.
Francisco Hodge
2

W przypadku wtyczki jQuery spróbuj tego

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

albo to

$.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
źródło
2

Na podstawie ARS81 „s odpowiedź (to tylko mecze nazwy klas rozpoczynające się), tutaj jest bardziej elastyczna wersja. Również hasClass()wersja wyrażenia regularnego.

Stosowanie: $('.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
źródło
2

To skutecznie usunie wszystkie nazwy klas, które zaczynają się prefixod classatrybutu węzła . Inne odpowiedzi nie obsługują elementów SVG (w momencie pisania tego), ale to rozwiązanie:

$.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
źródło
Czy nie byłoby bardziej efektywne utworzenie RegExpobiektu raz z każdego wywołania zwrotnego?
Emile Bergeron,
1
@EmileBergeron - tak, byłoby! Wprowadzę zmiany
vsync,
2

Miałem ten sam problem i przedstawiłem następujące, które wykorzystują metodę _.filter podkreślenia. Gdy odkryłem, że removeClass przyjmuje funkcję i udostępnia listę nazw klas, łatwo było przekształcić ją w tablicę i odfiltrować nazwę klasy, aby powrócić do metody 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
źródło
1
Czy możesz wyjaśnić, co robi podkreślenie w _.filter
bart
2

Możesz to również zrobić za pomocą waniliowego JavaScript za pomocą Element.classList . Nie ma potrzeby używania wyrażenia regularnego:

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

Uwaga: zauważ, że tworzymy Arraykopię classListprzed rozpoczęciem, jest to ważne, ponieważ classListjest to transmisja na żywo, DomTokenListktóra będzie aktualizowana po usunięciu klas.

kzar
źródło
1

Możesz także użyć classNamewłaściwości obiektu DOM elementu:

var $hello = $('#hello');
$('#hello').attr('class', $hello.get(0).className.replace(/\bcolor-\S+/g, ''));
Alexander Wallin
źródło
1

Ogólna funkcja usuwająca dowolną klasę zaczynającą się od 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
źródło
0

Dzielenie wyrażeń regularnych na granicy słów \bnie jest najlepszym rozwiązaniem:

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

lub jako 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 = classes.join(" ");
    });
    return this;
};
sarink
źródło
0

jeśli masz więcej niż jeden element o nazwie klasy „przykład”, aby usunąć klasy „kolor-” we wszystkich, możesz to zrobić: [używając jquery]

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

jeśli nie umieścisz [a-z1-9 -] * w wyrażeniu regularnym, nie usunie to klas, które mają numery lub niektóre „-” w ich nazwach.

mohammad eslahi sani
źródło
0

Jeśli chcesz tylko usunąć ostatni ustawiony kolor, poniższe mogą Ci odpowiadać.

W mojej sytuacji musiałem dodać klasę kolorów do tagu body na zdarzeniu kliknięcia i usunąć ostatni ustawiony kolor. W takim przypadku zapisujesz bieżący kolor, a następnie wyszukujesz znacznik danych, aby usunąć ostatni ustawiony kolor.

Kod:

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

Może nie być dokładnie tym, czego potrzebujesz, ale dla mnie było to i było to pierwsze pytanie SO, na które spojrzałem, więc pomyślałem, że podzielę się moim rozwiązaniem, na wypadek, gdyby komukolwiek to pomogło.

redfox05
źródło
To tutaj nie ma znaczenia. Mogłeś odpowiedzieć na swoje własne pytanie, ponieważ jest to zachęcające zachowanie na SO.
Emile Bergeron,
@Emile: To prawda. Mogę to zrobić, ponieważ nie jest to bezpośrednia odpowiedź na pierwotne pytanie. Czy mam zostawić tę odpowiedź, czy ją usunąć?
redfox05
W tym momencie jest to na własne ryzyko, nie zostało jeszcze odrzucone ani przegłosowane. Więc możesz przenieść to do własnego pytania bez ryzyka. Staraj się także unikać duplikatów, sprawdzając, czy jest już pytanie na ten temat.
Emile Bergeron,
0

Alternatywnym sposobem podejścia do tego problemu jest użycie atrybutów danych, które z natury są unikalne.

Ustawiłbyś kolor elementu takiego jak: $el.attr('data-color', 'red');

I stylizowałbyś to w css: [data-color="red"]{ color: tomato; }

To neguje potrzebę korzystania z klas, co powoduje efekt uboczny usuwania starych klas.

rorymorris89
źródło