jQuery removeClass подстановочный знак

371

Есть ли простой способ удалить все классы, соответствующие, например,

color-*

так что если у меня есть элемент:

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

после удаления было бы

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

Спасибо!

ассоциация теннисистов-профессионалов
источник
1
Регулярное выражение, как в «принятом ответе», нарушит границы непространственного слова. Я разместил альтернативное решение ниже. Также смотрите: stackoverflow.com/questions/57812/…
sarink
@KabirSarin принятый ответ был обновлен, чтобы исправить это.
Эмиль Бержерон
css wildcards surfingsuccess.com/css/…
Макс Ходжес

Ответы:

680

Функция removeClass принимает аргумент функции начиная с jQuery 1.4 .

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

Живой пример: http://jsfiddle.net/xa9xS/1409/

jimmystormig
источник
4
Я подумал, что стоит отметить, что это позволит захватить лидирующие пробелы соответствующих классов, которые не начинаются с самого начала. Javascript не поддерживает позитивный взгляд назад, поэтому вам придется использовать обходной путь группы захвата. Однако это спорный вопрос, потому что функция removeClass удалит для вас пробелы из строки вашего класса черезclasses = ( value || "" ).match( rnotwhite ) || [];
eephillip
Мне больше нравится это решение! Как я могу проверить, удаляются ли два или более классов? то есть sport-, nav-а color-?
lowtechsun
Как бы вы сделали это, чтобы соответствовать окончание класса, как *-color?
Круг B
3
@lowtechsun вы можете добавить в свое регулярное выражение, как это (color-|sport-|nav-). Это будет соответствовать color-, или sport-, или nav-. Итак, ответ выше стал бы /(^|\s)(color-|sport-|nav-)\S+/g.
Тележка
1
Принятый ответ правильный, но идиоматически, я бы использовал \ b, который соответствует любой границе слова, а не многословному (^ | \ s). Так, например, чтобы удалить все классы, состоящие из слова «магия», за которым следует неотрицательное целое число, и только те, которые я бы сопоставил с / \ bmagic \ d + \ b /.
CarlEdman
98
$('div').attr('class', function(i, c){
    return c.replace(/(^|\s)color-\S+/g, '');
});
Коби
источник
5
Мне это нравится, так как это уменьшает накладные расходы и позволяет сразу перейти к делу. Зачем использовать удалить класс, когда attr делает работу лучше?
Злой Дэн
2
я думаю, что вам нужно защитить от пустых классов ( c is undefined)? По крайней мере, когда я попробовал это ниже в моем плагине на этой странице, $('a').stripClass('post', 1)выкинуло «TypeError: Невозможно вызвать метод« замена »из неопределенного»
drzaus
1
@ Коби, да, я не думаю, что можно фильтровать атрибут и возвращать результат, который его не имеет - $('div[class]')должен возвращать только элементы с classнезависимо от того, имеют они значение или нет. сценарии тестирования: jsfiddle.net/drzaus/m83mv
drzaus
1
@ Коби - я думаю, что я вижу, что вы к чему; в крайних случаях, например, .removeProp('class')или .className=undefinedфильтр [class]все еще что-то возвращает, они просто undefined. Технически, у него все еще есть класс (в отличие от него .removeAttr('class'), поэтому он нарушает вашу функцию, но не мой вариант. Jsfiddle.net/drzaus/m83mv/4
drzaus
1
Добавление быстрого теста работает для меня:return c && c.replace(/\bcolor-\S+/g, '');
Ssmith
50

Я написал плагин, который делает это под названием alterClass - Удалить классы элементов с сопоставлением по шаблону. При желании добавить классы: https://gist.github.com/1517285

$( '#foo' ).alterClass( 'foo-* bar-*', 'foobar' )
Пит Б
источник
1
Очень хорошо, действительно ... помог мне повторно использовать некоторый код, где мне просто нужно было удалить Twitter Boostrapклассы, подобные этому:$(".search div").children('div').alterClass('span* row-fluid');
Лениэль Маккаферри
15

Я обобщил это в плагин Jquery, который принимает регулярное выражение в качестве аргумента.

Кофе:

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

Таким образом, для этого случая использование будет (как Coffee, так и Javascript):

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

Обратите внимание, что я использую Array.filterфункцию, которой нет в IE <9. Вместо этого вы можете использовать функцию фильтра Underscore или Google для полифилла, такого как WTFPL .

tremby
источник
11

Если вы хотите использовать его в других местах, я предлагаю вам расширение. Этот работает хорошо для меня.

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

Применение:

$(".myClass").removeClassStartingWith('color');
Чарли Гирао
источник
4

мы можем получить все классы с помощью .attr("class")Array, и 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]);
    }
}

демо: http://jsfiddle.net/L2A27/1/

meni181818
источник
Добавлено var prefix='color';и изменено ...if (classArr[i].substr(0, prefix.length) != prefix)
Rich C
4

Подобно @ tremby - х ответа , вот @ Коби в ответ как плагин , который будет соответствовать либо префиксы или суффиксы.

  • ех) полосы btn-miniи , btn-dangerно не btnкогда stripClass("btn-").
  • ех) полосы horsebtnи , cowbtnно не btn-miniили , btnкогдаstripClass('btn', 1)

Код:

$.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
источник
1
Для справки, я не согласен, что это проще.
Тремби
@tremby извините, я имел в виду более простое в типичном использовании (то есть префиксы и суффиксы), так как вам не нужно каждый раз писать регулярное выражение
drzaus
3
Я все еще не согласен. С вашим методом вы должны прочитать документацию и запомнить, какое именно значение endOrBeginдолжно быть. Это не говорит само за себя. Что сложного в написании регулярных выражений? /^match-at-start/и /match-at-end$/известны каждому разработчику JS. Но каждому свое.
Тремби
1
@tremby кроме регулярных выражений , просящие быть оскорбленными, не-регулярное выражение вариант более точно соответствует существующей подписи addClass, removeClassи toggleClass, которая , как известно каждому разработчику JQuery. Что сложного в чтении документации? ;)
drzaus
2
В чтении документации нет ничего сложного, но, как говорит @tremby, его решение не требует пояснений, а ваше решение требует документации. Самоочевидные решения проще по определению.
Франциско Ходж
2

Для плагина jQuery попробуйте это

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

или это

$.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
источник
2

На основе ARS81 «s ответа (что соответствует только именам классов , начиная с), вот более гибким вариантом. Также hasClass()версия регулярного выражения.

Применение: $('.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;
};
Паскаль Поллеунус
источник
2

Это эффективно удалит все имена классов, которые начинаются с атрибута prefixузла class. Другие ответы не поддерживают элементы SVG (на момент написания этого), но это решение:

$.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
источник
Не будет ли эффективнее создать RegExpобъект один раз из каждого обратного вызова?
Эмиль Бержерон
1
@EmileBergeron - да, это будет! Я сделаю изменения
vsync
2

У меня возникла та же проблема, и я пришел к следующему, в котором используется метод _.filter подчеркивания. Как только я обнаружил, что removeClass берет функцию и предоставляет вам список имен классов, было легко превратить это в массив и отфильтровать имя класса, чтобы вернуться к методу 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
источник
1
Можете ли вы объяснить , что подчеркивание делает в _.filter
Bart
2

Вы также можете сделать это с помощью обычного JavaScript, используя Element.classList . Нет необходимости использовать регулярное выражение:

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

Примечание: обратите внимание, что мы создаем Arrayкопию classListперед запуском, это важно, так classListкак это живое DomTokenListобновление, которое будет обновляться по мере удаления классов.

kzar
источник
Мне нравится этот метод, но есть ли способ сделать эту функцию более глобальной? Например; Чтобы дать параметр для функции с именем класса, который вы хотите удалить? Я думаю, что было бы еще лучше :)
Loosie94
2

Универсальная функция, которая удаляет любой класс, начинающийся с 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>

Фифи
источник
1

Вы также можете использовать classNameсвойство объекта DOM элемента:

var $hello = $('#hello');
$('#hello').attr('class', $hello.get(0).className.replace(/\bcolor-\S+/g, ''));
Александр Валлин
источник
0

Разделение регулярных выражений на границе слова \b- не лучшее решение для этого:

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

или как 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
источник
0

если у вас есть более одного элемента с именем класса 'example', чтобы удалить классы 'color-' во всех из них, вы можете сделать это: [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\-]*/,'');
}

если вы не введете [a-z1-9 -] * в свое регулярное выражение, оно не удалит классы, в именах которых есть число или несколько символов '-'.

Мохаммад Эслахи Сани
источник
0

Если вам просто нужно удалить последний установленный цвет, вам может подойти следующее.

В моей ситуации мне нужно было добавить класс цвета к тегу body в событии click и удалить последний цвет, который был установлен. В этом случае вы сохраняете текущий цвет, а затем ищите тег данных, чтобы удалить последний установленный цвет.

Код:

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

Может быть, это не совсем то, что вам нужно, но для меня это было, и это был первый SO вопрос, на который я посмотрел, поэтому подумал, что поделюсь своим решением, если оно кому-нибудь поможет.

redfox05
источник
Это не имеет значения здесь. Вы могли бы ответить на свой вопрос, так как в SO это поощряется.
Эмиль Бержерон
@Emile: это правда. Я мог бы сделать это, поскольку он не отвечает непосредственно на исходный вопрос. Должен ли я оставить этот ответ или удалить его?
redfox05
В этот момент это на ваш страх и риск, но за него еще не проголосовали. Таким образом, вы можете перенести его на свой вопрос без риска. Кроме того, попытайтесь избежать дубликатов, проверив, есть ли уже вопрос по этому поводу.
Эмиль Бержерон
0

Альтернативный способ решения этой проблемы - использовать атрибуты данных, которые по своей природе уникальны.

Вы бы установить цвет элемента, как: $el.attr('data-color', 'red');

И вы бы сделали это в CSS как: [data-color="red"]{ color: tomato; }

Это исключает необходимость использования классов, что имеет побочный эффект необходимости удаления старых классов.

rorymorris89
источник