web-dev-qa-db-fra.com

jQuery - Evénement Fire si la classe CSS a changé

comment puis-je déclencher un événement si la classe css a été ajoutée ou modifiée avec jQuery? Le changement de classe CSS déclenche-t-il l'événement jQuery change ()?

226
user237060

Chaque fois que vous modifiez une classe dans votre script, vous pouvez utiliser un trigger pour générer votre propre événement.

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

mais sinon, non, il n'y a pas de moyen imposé de déclencher un événement quand une classe change. change() ne se déclenche qu'après que la mise au point ait laissé une entrée dont l'entrée a été modifiée.

$(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>

Plus d'infos sur jQuery Triggers

215
Jason

IMHO la meilleure solution consiste à combiner deux réponses de @ RamboNo5 et @Jason

Je veux dire surcharger la fonction addClass et ajouter un événement personnalisé appelé 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
    });
});
132
Arash Milani

Je vous suggère de remplacer la fonction addClass. Vous pouvez le faire de cette façon:

// 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
});
52
RamboNo5

Si vous souhaitez détecter un changement de classe, le meilleur moyen consiste à utiliser l'observateur de mutations, qui vous permet de contrôler totalement tout changement d'attribut. Cependant, vous devez définir vous-même l'auditeur et l'ajouter à l'élément que vous écoutez. La bonne chose est que vous n'avez pas besoin de déclencher quoi que ce soit manuellement une fois que l'auditeur est ajouté.

$(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
    }

});
});

Dans cet exemple, l'écouteur d'événements est ajouté à chaque élément, mais vous ne le souhaitez pas dans la plupart des cas (économiser de la mémoire). Ajoutez cet écouteur "attrchange" à l'élément que vous souhaitez observer.

49
Mr Br

Juste une preuve de concept:

Examinez le Gist pour voir des annotations et rester à jour:

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));

L'utilisation est assez simple, il suffit d'ajouter un nouveau gestionnaire de liste sur le nœud que vous souhaitez observer et de manipuler les classes comme d'habitude:

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');
20
yckart

change() ne se déclenche pas lorsqu'une classe CSS est ajoutée ou supprimée ou que la définition change. Il se déclenche dans certaines circonstances, par exemple lorsqu'une valeur de zone de sélection est sélectionnée ou désélectionnée.

Je ne sais pas si vous voulez dire si la définition de la classe CSS est modifiée (ce qui peut être fait par programmation mais est fastidieux et généralement pas recommandé) ou si une classe est ajoutée ou supprimée à un élément. Il n'y a aucun moyen de capturer de manière fiable ce qui se passe dans les deux cas.

Vous pouvez bien sûr créer votre propre événement pour cela, mais cela ne peut être décrit que comme advisory . Il ne capturera pas le code qui ne vous appartient pas.

Sinon, vous pouvez remplacer/remplacer les méthodes addClass() (etc) dans jQuery, mais cela ne sera pas capturé lorsque cela sera fait via Javascript Vanilla (bien que je suppose que vous puissiez également remplacer ces méthodes).

7
cletus

Il y a encore un moyen sans que déclenche un événement personnalisé

Un plug-in jQuery pour surveiller les modifications CSS des éléments HTML par Rick Strahl

Citant d'en haut 

Le plug-in watch fonctionne en se connectant à DOMAttrModified dans FireFox, à onPropertyChanged dans Internet Explorer, ou en utilisant une minuterie avec setInterval pour gérer la détection des modifications pour les autres navigateurs . Malheureusement, WebKit ne prend pas en charge DOMAttrModified de manière cohérente à le moment, donc Safari et Chrome doivent actuellement utiliser le plus lent mécanisme setInterval.

7
Amitd

en utilisant la dernière mutation de 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
            });

// tout code qui met à jour div en ayant la classe required-entry qui est dans $ target like $ target.addClass ('search-class');

6
Hassan Ali Shahzad

Bonne question. J'utilise le menu déroulant Bootstrap et ai besoin d'exécuter un événement lorsqu'une liste déroulante Bootstrap était masquée. Lorsque la liste déroulante est ouverte, le div contenant le nom de classe "button-group" ajoute une classe de "open"; et le bouton lui-même a un attribut "aria-expand" défini sur true. Lorsque la liste déroulante est fermée, cette classe "open" est supprimée du div qui le contient et aria-expand est passée de true à false.

Cela m'a amené à cette question, comment détecter le changement de classe.

Avec Bootstrap, il y a des "événements de dropdown" qui peuvent être détectés. Recherchez les "événements de type" dans ce lien . http://www.w3schools.com/bootstrap/bootstrap_ref_js_dropdown.asp

Voici un exemple rapide d'utilisation de cet événement dans un menu déroulant Bootstrap.

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

Maintenant, je réalise que ceci est plus spécifique que la question générale qui est posée. Mais j'imagine que d'autres développeurs essayant de détecter un événement ouvert ou fermé avec un Bootstrap Dropdown trouveront cela utile. Comme moi, ils peuvent commencer par essayer simplement de détecter un changement de classe d'élément (ce qui n'est apparemment pas si simple). Merci.

5
Ken Palmer

Si vous devez déclencher un événement spécifique, vous pouvez remplacer la méthode addClass () pour déclencher un événement personnalisé appelé 'classadded'.

Voici comment:

(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
    // ...
});
4
micred

Vous pouvez lier l'événement DOMSubtreeModified. J'ajoute un exemple ici:

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/

3
Sativa Diva
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');
});
0
Jérome Obbiet

si vous connaissez un événement qui a changé la classe en premier lieu, vous pouvez utiliser un léger retard sur le même événement et cocher la pour la classe.

//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/

0
Nikos Tsagkas