Come attivare un evento al cambio di classe utilizzando jQuery?


91

Mi piacerebbe avere qualcosa come:

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

Risposte:


172

Non viene generato alcun evento quando una classe cambia. L'alternativa è generare manualmente un evento quando si modifica programmaticamente la classe:

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

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

AGGIORNARE

Questa domanda sembra raccogliere alcuni visitatori, quindi ecco un aggiornamento con un approccio che può essere utilizzato senza dover modificare il codice esistente utilizzando il nuovo 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>

Tieni presente che MutationObserverè disponibile solo per i browser più recenti, in particolare Chrome 26, FF 14, IE 11, Opera 15 e Safari 6. Vedi MDN per maggiori dettagli. Se è necessario supportare i browser legacy, sarà necessario utilizzare il metodo che ho delineato nel mio primo esempio.


A completamento di questa risposta, ho trovato questo: stackoverflow.com/a/1950052/1579667
— Benj

1
@ Benj È la stessa della mia risposta originale (ad es. Utilizzando trigger()) anche se si noti che è molto obsoleta a causa dell'uso di bind(). Non sono sicuro di come "completi" qualcosa, però
— Rory McCrossan il

Nel mio caso avevo bisogno di attivare un evento quando un nodo dom ha una classe specifica che MutationObserverfunziona per me
— Mario

1
Questa è una forma perfezionata di questa soluzione con filtro stackoverflow.com/a/42121795/12074818
— MVDeveloper1

20

È possibile sostituire le funzioni jQuery addClass e removeClass originali con le proprie che chiamerebbero le funzioni originali e quindi attivare un evento personalizzato. (Utilizzo di una funzione anonima autoinvocante per contenere il riferimento alla funzione originale)

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

Quindi il resto del codice sarà semplice come ti aspetteresti.

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

Aggiornare:

Questo approccio presuppone che le classi verranno modificate solo tramite i metodi jQuery addClass e removeClass. Se le classi vengono modificate in altri modi (come la manipolazione diretta dell'attributo di classe tramite l'elemento DOM), utilizzare qualcosa di simileMutationObserver sarebbe necessario s come spiegato nella risposta accettata qui.

Anche come un paio di miglioramenti a questi metodi:

  • Attiva un evento per ogni classe che viene aggiunta ( classAdded) o rimossa ( classRemoved) con la classe specifica passata come argomento alla funzione di callback e attivata solo se la particolare classe è stata effettivamente aggiunta (non presente in precedenza) o rimossa (era presente in precedenza)
  • Attiva solo classChangedse le classi vengono effettivamente modificate

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

Con queste funzioni di sostituzione puoi quindi gestire qualsiasi classe modificata tramite classChanged o classi specifiche aggiunte o rimosse controllando l'argomento della funzione di callback:

$(document).on('classAdded', '#myElement', function(event, className) {
    if(className == "something") { /* do something */ }
});

1
Questo funziona bene, ma nel "resto del codice", il gestore di eventi dovrebbe essere delegata al selettore di destinazione per consentire il legame con nuovi elementi: $(parent_selector).on('classChanged', target_selector, function(){ /*...*/ });. Mi ci è voluto un po 'per capire perché i miei elementi creati dinamicamente non hanno attivato il gestore. Vedi learn.jquery.com/events/event-delegation
— Timm


2

puoi usare qualcosa del genere:

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

$(Selector).trigger('ClassChanged')

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

ma per il resto no, non esiste una funzione predefinita per attivare un evento quando una classe cambia.

Maggiori informazioni sui trigger qui


1
Il gestore dell'evento deve essere lo stesso elemento che attiva l'evento. $ (questo) .addClass ('someClass'); $ (Selector) .trigger ('ClassChanged') // Deve essere lo stesso selettore $ (Selector) .bind ('ClassChanged', data, function () {// stuff});
— Meko Perez Estevez

3
Sembra copiato da qui, se sì allora va bene se si fornisce collegamento troppo stackoverflow.com/questions/1950038/...
— Satinder Singh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.