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.