105 votes

Comment déclencher un événement lors d'un changement de classe en utilisant jQuery?

Je voudrais avoir quelque chose comme:

$('#myDiv').bind('class "soumission ok" ajouté'){
    alert('class "soumission ok" a été ajouté');
});

217voto

Rory McCrossan Points 69838

Il n'y a pas d'événement déclenché lorsqu'une classe change. L'alternative est de déclencher manuellement un événement lorsque vous changez le class programmatiquement :

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

// dans un autre fichier js, loin, très loin
$('#myDiv').on('classChange', function() {
     // faire quelque chose
});

MISE À JOUR - 2015

Cette question semble attirer quelques visiteurs, voici donc une mise à jour avec une approche qui peut être utilisée sans avoir à modifier le code existant en utilisant le nouveau MutationObserver :

var $div = $("#foo");
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    var attributeValue = $(mutation.target).prop(mutation.attributeName);
    console.log("La classe de l'attribut a été changée en :", attributeValue);
  });
});

observer.observe($div[0], {
  attributes: true,
  attributeFilter: ['class']
});

$div.addClass('red');

.red {
  color: #C00;
}

#foo.bar

Sachez que le MutationObserver est uniquement disponible pour les navigateurs plus récents, spécifiquement Chrome 26, FF 14, IE 11, Opera 15 et Safari 6. Consultez la MDN pour plus de détails. Si vous avez besoin de prendre en charge les anciens navigateurs, vous devrez utiliser la méthode que j'ai décrite dans mon premier exemple.


MISE À JOUR - 2022

Voici une implémentation de ce qui précède enveloppée dans une méthode d'extension jQuery :

// méthode d'extension :
$.fn.onClassChange = function(cb) {
  return $(this).each((_, el) => {
    new MutationObserver(mutations => {
      mutations.forEach(mutation => cb && cb(mutation.target, mutation.target.className));
    }).observe(el, {
      attributes: true,
      attributeFilter: ['class'] // écouter uniquement les changements d'attribut de classe
    });
  });
}

// utilisation :
const $foo = $("#foo").onClassChange((el, newClass) => console.log(`#${el.id} a été mis à jour avec la classe : ${newClass}`));
const $fizz = $("#fizz").onClassChange((el, newClass) => console.log(`#${el.id} a été mis à jour avec la classe : ${newClass}`));

// déclencher
$('#trigger').on('click', () => {
  $foo.removeClass('red');
  $fizz.addClass('green dark-bg');
});

.red {
  color: #C00;
}

.green {
  color: #0C0;
}

.dark-bg {
  background-color: #666;
}

Changer les classes
#foo.bar
#fizz.buzz

24voto

Nickolas Hook Points 724

Vous pourriez remplacer les fonctions d'origine jQuery addClass et removeClass par les vôtres qui appeleraient les fonctions d'origine, puis déclencheraient un événement personnalisé. (Utilisation d'une fonction anonyme auto-invoquante pour contenir la référence de la fonction d'origine)

(function( func ) {
    $.fn.addClass = function() { // remplacer la fonction existante sur $.fn
        func.apply( this, arguments ); // appeler la fonction d'origine
        this.trigger('classChanged'); // déclencher l'événement personnalisé
        return this; // conserver la chaînabilité de jQuery
    }
})($.fn.addClass); // passer la fonction d'origine en argument

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

Ensuite, le reste de votre code serait aussi simple que vous vous y attendez.

$(sélecteur).on('classChanged', function(){ /*...*/ });

Mise à jour :

JS Fiddle Demo

Cette approche suppose que les classes seront modifiées uniquement via les méthodes jQuery addClass et removeClass. Si les classes sont modifiées d'autres façons (comme la manipulation directe de l'attribut de classe à travers l'élément DOM), l'utilisation de quelque chose comme les MutationObservers comme expliqué dans la réponse acceptée ici serait nécessaire.

Aussi, pour quelques améliorations à ces méthodes :

  • Déclencher un événement pour chaque classe ajoutée (classAdded) ou supprimée (classRemoved) avec la classe spécifique passée en argument à la fonction de rappel et déclencher seulement si la classe particulière a réellement été ajoutée (n'était pas présente auparavant) ou supprimée (était présente auparavant)

  • Ne déclencher classChanged que si des classes sont effectivement modifiées

    (function( func ) {
        $.fn.addClass = function(n) { // remplacer la fonction existante sur $.fn
            this.each(function(i) { // pour chaque élément dans la collection
                var $this = $(this); // 'this' est l'élément DOM dans ce contexte
                var prevClasses = this.getAttribute('class'); // noter ses classes d'origine
                var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString(); // maintenir la prise en charge des arguments de type fonction
                $.each(classNames.split(/\s+/), function(index, className) { // permettre l'ajout de plusieurs classes
                    if( !$this.hasClass(className) ) { // seulement quand la classe n'est pas déjà présente
                        func.call( $this, className ); // appeler la fonction d'origine pour ajouter la classe
                        $this.trigger('classAdded', className); // déclencher un événement classAdded
                    }
                });
                if( prevClasses != this.getAttribute('class') ) $this.trigger('classChanged'); // déclencher l'événement classChanged
            });
            return this; // conserver la chaînabilité de jQuery
        }
    })($.fn.addClass); // passer la fonction d'origine en 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);
                    }
                });
                if( prevClasses != this.getAttribute('class') ) $this.trigger('classChanged');
            });
            return this;
        }
    })($.fn.removeClass);

Avec ces fonctions de remplacement, vous pouvez ensuite gérer toute classe modifiée via classChanged ou des classes spécifiques ajoutées ou supprimées en vérifiant l'argument de la fonction de rappel :

$(document).on('classAdded', '#monElement', function(event, className) {
    if(className == "quelquechose") { /* faire quelque chose */ }
});

10voto

Satinder singh Points 3089

Utilisez trigger pour déclencher votre propre événement. Chaque fois que vous changez de classe, ajoutez un trigger avec le nom

JS Fiddle DEMO

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

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

    alert("Fond rouge défini");
});

1voto

Deep Sharma Points 3176

Vous pouvez utiliser quelque chose comme ceci :

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

$(Selector).trigger('ClassChanged')

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

mais sinon, non, il n'y a pas de fonction prédéfinie pour déclencher un événement lorsque une classe change.

En savoir plus sur les déclencheurs ici

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X