Wie kann ein Ereignis beim Klassenwechsel mit jQuery ausgelöst werden?

89

Ich hätte gerne so etwas wie:

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

Antworten:

167

Es wird kein Ereignis ausgelöst, wenn sich eine Klasse ändert. Die Alternative besteht darin, ein Ereignis manuell auszulösen, wenn Sie die Klasse programmgesteuert ändern:

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

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

AKTUALISIEREN

Diese Frage scheint einige Besucher zu sammeln, daher hier ein Update mit einem Ansatz, der verwendet werden kann, ohne dass vorhandener Code mit dem neuen geändert werden muss 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>

Beachten Sie, dass das MutationObservernur für neuere Browser verfügbar ist, insbesondere für Chrome 26, FF 14, IE 11, Opera 15 und Safari 6. Weitere Informationen finden Sie unter MDN . Wenn Sie ältere Browser unterstützen müssen, müssen Sie die in meinem ersten Beispiel beschriebene Methode verwenden.

Rory McCrossan
quelle
In Vervollständigung dieser Antwort fand ich dies: stackoverflow.com/a/1950052/1579667
Benj
1
@Benj Das ist das gleiche wie meine ursprüngliche Antwort (dh mit trigger()), obwohl zu beachten ist, dass es aufgrund der Verwendung von sehr veraltet ist bind(). Ich bin mir jedoch nicht sicher, wie es irgendetwas "vervollständigt"
Rory McCrossan
In meinem Fall musste ich ein Ereignis auslösen, wenn ein Dom-Knoten eine bestimmte Klasse MutationObserverfür mich hat
Mario
Dies ist eine verbesserte Form dieser Lösung mit Filter stackoverflow.com/a/42121795/12074818
MVDeveloper1
20

Sie können die ursprünglichen Funktionen jQuery addClass und removeClass durch Ihre eigenen Funktionen ersetzen, die die ursprünglichen Funktionen aufrufen und dann ein benutzerdefiniertes Ereignis auslösen. (Verwenden einer selbstaufrufenden anonymen Funktion, um die ursprüngliche Funktionsreferenz zu enthalten)

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

Dann wäre der Rest Ihres Codes so einfach, wie Sie es erwarten würden.

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

Aktualisieren:

Bei diesem Ansatz wird davon ausgegangen, dass die Klassen nur über die Methoden jQuery addClass und removeClass geändert werden. Wenn Klassen auf andere Weise geändert werden (z. B. durch direkte Manipulation des Klassenattributs über das DOM-Element), ist die Verwendung von MutationObservers wie in der hier akzeptierten Antwort erläutert erforderlich.

Auch als ein paar Verbesserungen an diesen Methoden:

  • Lösen Sie ein Ereignis für jede Klasse aus, die hinzugefügt ( classAdded) oder entfernt ( classRemoved) wird, wobei die bestimmte Klasse als Argument an die Rückruffunktion übergeben und nur ausgelöst wird, wenn die bestimmte Klasse tatsächlich hinzugefügt (zuvor nicht vorhanden) oder entfernt (zuvor vorhanden) wurde.
  • classChangedWird nur ausgelöst, wenn tatsächlich Klassen geändert werden

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

Mit diesen Ersetzungsfunktionen können Sie dann jede Klasse behandeln, die über classChanged geändert wurde, oder bestimmte Klassen, die hinzugefügt oder entfernt werden, indem Sie das Argument für die Rückruffunktion überprüfen:

$(document).on('classAdded', '#myElement', function(event, className) {
    if(className == "something") { /* do something */ }
});
Nickolas Hook
quelle
1
Dies funktioniert einwandfrei, aber im "Rest des Codes" sollte der Ereignishandler an den Zielselektor delegiert werden, um die Bindung an neue Elemente zu ermöglichen : $(parent_selector).on('classChanged', target_selector, function(){ /*...*/ });. Ich habe eine Weile gebraucht, um zu sehen, warum meine dynamisch erstellten Elemente den Handler nicht ausgelöst haben. Siehe learn.jquery.com/events/event-delegation
Timm
2

Sie können so etwas verwenden:

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

$(Selector).trigger('ClassChanged')

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

Andernfalls gibt es keine vordefinierte Funktion zum Auslösen eines Ereignisses, wenn sich eine Klasse ändert.

Lesen Sie mehr über Trigger hier

Deep Sharma
quelle
1
Der Handler des Ereignisses muss dasselbe Element sein, das das Ereignis auslöst. $ (this) .addClass ('someClass'); $ (Selector) .trigger ('ClassChanged') // Es muss derselbe Selector sein $ (Selector) .bind ('ClassChanged', data, function () {// stuff});
Meko Perez Estevez
3
Scheint, Sie haben von hier kopiert, wenn ja, dann gut, wenn Sie auch einen Link bereitstellen stackoverflow.com/questions/1950038/…
Satinder singh