Как запустить событие при изменении класса с помощью jQuery?

Я бы хотел иметь что-нибудь вроде:

$('#myDiv').bind('class "submission ok" added'){
    alert('class "submission ok" has been added');
});

person Matoeil    schedule 16.10.2013    source источник


Ответы (4)


При изменении класса событие не возникает. Альтернативой является создание события вручную при программном изменении класса:

$someElement.on('event', function() {
    $('#myDiv').addClass('submission-ok').trigger('classChange');
});

// in another js file, far, far away
$('#myDiv').on('classChange', function() {
     // do stuff
});

ОБНОВЛЕНИЕ

Этот вопрос, похоже, собирает некоторых посетителей, поэтому вот обновление с подходом, который можно использовать без необходимости изменять существующий код с помощью нового MutationObserver:

var $div = $("#foo");
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    if (mutation.attributeName === "class") {
      var attributeValue = $(mutation.target).prop(mutation.attributeName);
      console.log("Class attribute changed to:", attributeValue);
    }
  });
});
observer.observe($div[0], {
  attributes: true
});

$div.addClass('red');
.red { color: #C00; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo" class="bar">#foo.bar</div>

Имейте в виду, что MutationObserver доступен только для новых браузеров, в частности Chrome 26, FF 14, IE 11, Opera 15 и Safari 6. См. MDN для получения дополнительных сведений. Если вам нужно поддерживать устаревшие браузеры, вам нужно будет использовать метод, который я описал в моем первом примере.

person Rory McCrossan    schedule 16.10.2013
comment
В завершение этого ответа я нашел следующее: stackoverflow.com/a/1950052/1579667 - person Benj; 27.10.2017
comment
@Benj Это то же самое, что и мой исходный ответ (например, с использованием trigger()), хотя обратите внимание, что он очень устарел из-за использования bind(). Я не уверен, как это что-то «завершает», хотя - person Rory McCrossan; 15.02.2018
comment
В моем случае мне нужно было запустить событие, когда у dom node есть определенный класс MutationObserver работает для меня - person Mario; 21.03.2019
comment
Это улучшенная форма этого решения с фильтром stackoverflow.com/a/42121795/12074818 - person MVDeveloper1; 19.08.2020

Вы можете заменить исходные функции jQuery addClass и removeClass своими собственными, которые будут вызывать исходные функции, а затем запускать настраиваемое событие. (Использование самозаполняющейся анонимной функции для хранения исходной ссылки на функцию)

(function( func ) {
    $.fn.addClass = function() { // replace the existing function on $.fn
        func.apply( this, arguments ); // invoke the original function
        this.trigger('classChanged'); // trigger the custom event
        return this; // retain jQuery chainability
    }
})($.fn.addClass); // pass the original function as an argument

(function( func ) {
    $.fn.removeClass = function() {
        func.apply( this, arguments );
        this.trigger('classChanged');
        return this;
    }
})($.fn.removeClass);

Тогда остальная часть вашего кода будет настолько простой, насколько вы ожидаете.

$(selector).on('classChanged', function(){ /*...*/ });

Обновлять:

Этот подход предполагает, что классы будут изменены только с помощью методов jQuery addClass и removeClass. Если классы изменяются другими способами (такими как прямое манипулирование атрибутом класса через элемент DOM), необходимо использовать что-то вроде MutationObservers, как описано в принятом ответе здесь.

Также как пара улучшений этих методов:

  • Запуск события для каждого класса, добавляемого (classAdded) или удаляемого (classRemoved), при этом конкретный класс передается в качестве аргумента функции обратного вызова и запускается только в том случае, если конкретный класс был фактически добавлен (ранее не присутствовал) или удален (присутствовал ранее)
  • Запускать classChanged только в случае фактического изменения каких-либо классов

    (function( func ) {
        $.fn.addClass = function(n) { // replace the existing function on $.fn
            this.each(function(i) { // for each element in the collection
                var $this = $(this); // 'this' is DOM element in this context
                var prevClasses = this.getAttribute('class'); // note its original classes
                var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString(); // retain function-type argument support
                $.each(classNames.split(/\s+/), function(index, className) { // allow for multiple classes being added
                    if( !$this.hasClass(className) ) { // only when the class is not already present
                        func.call( $this, className ); // invoke the original function to add the class
                        $this.trigger('classAdded', className); // trigger a classAdded event
                    }
                });
                prevClasses != this.getAttribute('class') && $this.trigger('classChanged'); // trigger the classChanged event
            });
            return this; // retain jQuery chainability
        }
    })($.fn.addClass); // pass the original function as an argument
    
    (function( func ) {
        $.fn.removeClass = function(n) {
            this.each(function(i) {
                var $this = $(this);
                var prevClasses = this.getAttribute('class');
                var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString();
                $.each(classNames.split(/\s+/), function(index, className) {
                    if( $this.hasClass(className) ) {
                        func.call( $this, className );
                        $this.trigger('classRemoved', className);
                    }
                });
                prevClasses != this.getAttribute('class') && $this.trigger('classChanged');
            });
            return this;
        }
    })($.fn.removeClass);
    

С помощью этих функций замены вы можете обрабатывать любой класс, измененный с помощью classChanged, или определенные классы, добавляемые или удаляемые, путем проверки аргумента функции обратного вызова:

$(document).on('classAdded', '#myElement', function(event, className) {
    if(className == "something") { /* do something */ }
});
person Nickolas Hook    schedule 06.08.2015
comment
Это работает нормально, но в остальной части кода обработчик событий должен быть делегирован целевому селектору, чтобы разрешить привязку к новым элементам: $(parent_selector).on('classChanged', target_selector, function(){ /*...*/ });. Мне потребовалось время, чтобы понять, почему мои динамически созданные элементы не запускают обработчик. См. learn.jquery.com/events/event-delegation. - person Timm; 24.10.2015

Используйте trigger, чтобы запустить собственное событие. Когда вы меняете класс, добавляйте триггер с именем

JS Fiddle DEMO

$("#main").on('click', function () {
    $("#chld").addClass("bgcolorRed").trigger("cssFontSet");
});

$('#chld').on('cssFontSet', function () {

    alert("Red bg set ");
});
person Satinder singh    schedule 16.10.2013

вы можете использовать что-то вроде этого:

$(this).addClass('someClass');

$(Selector).trigger('ClassChanged')

$(otherSelector).bind('ClassChanged', data, function(){//stuff });

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

Подробнее о триггерах см. здесь

person Deep Sharma    schedule 16.10.2013
comment
Обработчик события должен быть тем же элементом, который запускает событие. $ (это) .addClass ('someClass'); $ (Selector) .trigger ('ClassChanged') // Это должен быть тот же Selector $ (Selector) .bind ('ClassChanged', data, function () {// stuff}); - person Meko Perez Estevez; 16.10.2013
comment
Кажется, вы скопировали отсюда, если да, то хорошо, если вы тоже предоставите ссылку stackoverflow.com/questions/1950038/ - person Satinder singh; 16.10.2013