jQuery - событие Fire, если класс CSS изменился

Как я могу запустить событие, если класс css был добавлен или изменен с помощью jQuery? Запускает ли изменение класса CSS событие jQuery change()?

13 ответов

Решение

Всякий раз, когда вы меняете класс в вашем скрипте, вы можете использовать trigger поднять свое собственное событие.

$(this).addClass('someClass');
$(mySelector).trigger('cssClassChanged')
....
$(otherSelector).bind('cssClassChanged', data, function(){ do stuff });

но в противном случае, нет, нет никакого запутанного способа вызвать событие, когда класс меняется. change() только срабатывает после того, как фокус оставляет вход, чей вход был изменен.

$(function() {
  var button = $('.clickme')
      , box = $('.box')
  ;
  
  button.on('click', function() { 
    box.removeClass('box');
    $(document).trigger('buttonClick');
  });
            
  $(document).on('buttonClick', function() {
    box.text('Clicked!');
  });
});
.box { background-color: red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="box">Hi</div>
<button class="clickme">Click me</button>

Подробнее о триггерах jQuery

ИМХО, лучшее решение - объединить два ответа @RamboNo5 и @Jason

Я имею в виду переопределение функции addClass и добавление пользовательского события под названием cssClassChanged

// Create a closure
(function(){
    // Your base, I'm in it!
    var originalAddClassMethod = jQuery.fn.addClass;

    jQuery.fn.addClass = function(){
        // Execute the original method.
        var result = originalAddClassMethod.apply( this, arguments );

        // trigger a custom event
        jQuery(this).trigger('cssClassChanged');

        // return the original result
        return result;
    }
})();

// document ready function
$(function(){
    $("#YourExampleElementID").bind('cssClassChanged', function(){ 
        //do stuff here
    });
});

Если вы хотите обнаружить изменение класса, лучше всего использовать Mutation Observers, который дает вам полный контроль над любым изменением атрибута. Однако вам нужно определить слушателя самостоятельно и добавить его к элементу, который вы слушаете. Хорошо, что вам не нужно ничего запускать вручную после добавления слушателя.

$(function() {
(function($) {
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

    $.fn.attrchange = function(callback) {
        if (MutationObserver) {
            var options = {
                subtree: false,
                attributes: true
            };

            var observer = new MutationObserver(function(mutations) {
                mutations.forEach(function(e) {
                    callback.call(e.target, e.attributeName);
                });
            });

            return this.each(function() {
                observer.observe(this, options);
            });

        }
    }
})(jQuery);

//Now you need to append event listener
$('body *').attrchange(function(attrName) {

    if(attrName=='class'){
            alert('class changed');
    }else if(attrName=='id'){
            alert('id changed');
    }else{
        //OTHER ATTR CHANGED
    }

});
});

В этом примере прослушиватель событий добавляется к каждому элементу, но в большинстве случаев вы этого не хотите (экономьте память). Добавьте этот слушатель "attrchange" к элементу, который вы хотите наблюдать.

Я бы предложил переопределить функцию addClass. Вы можете сделать это следующим образом:

// Create a closure
(function(){
    // Your base, I'm in it!
    var originalAddClassMethod = jQuery.fn.addClass;

    jQuery.fn.addClass = function(){
        // Execute the original method.
        var result = originalAddClassMethod.apply( this, arguments );

        // call your function
        // this gets called everytime you use the addClass method
        myfunction();

        // return the original result
        return result;
    }
})();

// document ready function
$(function(){
    // do stuff
});

Просто подтверждение концепции:

Посмотрите на суть, чтобы увидеть некоторые аннотации и оставаться в курсе:

https://gist.github.com/yckart/c893d7db0f49b1ea4dfb

(function ($) {
  var methods = ['addClass', 'toggleClass', 'removeClass'];

  $.each(methods, function (index, method) {
    var originalMethod = $.fn[method];

    $.fn[method] = function () {
      var oldClass = this[0].className;
      var result = originalMethod.apply(this, arguments);
      var newClass = this[0].className;

      this.trigger(method, [oldClass, newClass]);

      return result;
    };
  });
}(window.jQuery || window.Zepto));

Использование довольно просто, просто добавьте новый слушатель на узел, который вы хотите наблюдать, и управляйте классами, как обычно:

var $node = $('div')

// listen to class-manipulation
.on('addClass toggleClass removeClass', function (e, oldClass, newClass) {
  console.log('Changed from %s to %s due %s', oldClass, newClass, e.type);
})

// make some changes
.addClass('foo')
.removeClass('foo')
.toggleClass('foo');

Используя последнюю мутацию JQuery

var $target = jQuery(".required-entry");
            var observer = new MutationObserver(function(mutations) {
                mutations.forEach(function(mutation) {
                    if (mutation.attributeName === "class") {
                        var attributeValue = jQuery(mutation.target).prop(mutation.attributeName);
                        if (attributeValue.indexOf("search-class") >= 0){
                            // do what you want
                        }
                    }
                });
            });
            observer.observe($target[0],  {
                attributes: true
            });

// любой код, который обновляет div с классом required-entry, который находится в $target как $target.addClass('search-class');

change() не срабатывает при добавлении или удалении CSS-класса или изменении определения. Он срабатывает в обстоятельствах, например, когда выбрано или не выбрано значение поля выбора.

Я не уверен, имеете ли вы в виду, если определение класса CSS изменено (что может быть сделано программно, но утомительно и обычно не рекомендуется) или класс добавлен или удален в элемент. Нет способа надежно зафиксировать это в любом случае.

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

В качестве альтернативы вы можете переопределить / заменить addClass() (и т. д.) методов в jQuery, но они не будут записываться, когда это делается через ванильный Javascript (хотя я думаю, что вы также можете заменить эти методы).

Есть еще один способ, не вызывая пользовательское событие

Плагин jQuery для отслеживания изменений CSS в HTML-элементах. Автор Rick Strahl

Цитирование сверху

Плагин наблюдения работает путем подключения к DOMAttrModified в FireFox, к onPropertyChanged в Internet Explorer или с помощью таймера с setInterval для обработки обнаружения изменений для других браузеров. К сожалению, в настоящее время WebKit не поддерживает DOMAttrModified последовательно, поэтому Safari и Chrome в настоящее время вынуждены использовать более медленный механизм setInterval.

Хороший вопрос. Я использую выпадающее меню Bootstrap, и мне нужно было выполнить событие, когда выпадающее меню Bootstrap было скрыто. Когда раскрывающийся список открыт, содержащий div с именем класса "button-group" добавляет класс "open"; и сама кнопка имеет расширенный атрибут aria, установленный в true. Когда раскрывающийся список закрыт, этот класс "open" удаляется из содержащего div, и aria-extended переключается с true на false.

Это привело меня к этому вопросу о том, как обнаружить изменение класса.

С помощью Bootstrap существуют "выпадающие события", которые можно обнаружить. Посмотрите на "Dropdown Events" по этой ссылке. http://www.w3schools.com/bootstrap/bootstrap_ref_js_dropdown.asp

Вот быстрый и грязный пример использования этого события в выпадающем меню Bootstrap.

$(document).on('hidden.bs.dropdown', function(event) {
    console.log('closed');
});

Теперь я понимаю, что это более конкретно, чем общий вопрос, который задают. Но я думаю, что другие разработчики, пытающиеся обнаружить открытое или закрытое событие с помощью Bootstrap Dropdown, найдут это полезным. Как и я, они могут сначала пойти по пути простой попытки обнаружить изменение класса элемента (что, очевидно, не так просто). Благодарю.

Если вам нужно вызвать определенное событие, вы можете переопределить метод addClass(), чтобы запустить пользовательское событие с именем "classadded".

Вот как:

(function() {
    var ev = new $.Event('classadded'),
        orig = $.fn.addClass;
    $.fn.addClass = function() {
        $(this).trigger(ev, arguments);
        return orig.apply(this, arguments);
    }
})();

$('#myElement').on('classadded', function(ev, newClasses) {
    console.log(newClasses + ' added!');
    console.log(this);
    // Do stuff
    // ...
});

Вы можете связать событие DOMSubtreeModified. Я добавляю пример здесь:

HTML

<div id="mutable" style="width:50px;height:50px;">sjdfhksfh<div>
<div>
  <button id="changeClass">Change Class</button>
</div>

JavaScript

$(document).ready(function() {
  $('#changeClass').click(function() {
    $('#mutable').addClass("red");
  });

  $('#mutable').bind('DOMSubtreeModified', function(e) {
      alert('class changed');
  });
});

http://jsfiddle.net/hnCxK/13/

var timeout_check_change_class;

function check_change_class( selector )
{
    $(selector).each(function(index, el) {
        var data_old_class = $(el).attr('data-old-class');
        if (typeof data_old_class !== typeof undefined && data_old_class !== false) 
        {

            if( data_old_class != $(el).attr('class') )
            {
                $(el).trigger('change_class');
            }
        }

        $(el).attr('data-old-class', $(el).attr('class') );

    });

    clearTimeout( timeout_check_change_class );
    timeout_check_change_class = setTimeout(check_change_class, 10, selector);
}
check_change_class( '.breakpoint' );


$('.breakpoint').on('change_class', function(event) {
    console.log('haschange');
});

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

//this is not the code you control
$('input').on('blur', function(){
    $(this).addClass('error');
    $(this).before("<div class='someClass'>Warning Error</div>");
});

//this is your code
$('input').on('blur', function(){
    var el= $(this);
    setTimeout(function(){
        if ($(el).hasClass('error')){ 
            $(el).removeClass('error');
            $(el).prev('.someClass').hide();
        }
    },1000);
});

http://jsfiddle.net/GuDCp/3/

Другие вопросы по тегам