如何使用 jQuery 触发类更改事件?

我想要这样的东西:

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

you can use something like this:

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


$(Selector).trigger('ClassChanged')


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

but otherwise, no, there's no predefined function to fire an event when a class changes.

Read more about triggers here

Use trigger to fire your own event. When ever you change class add trigger with name

JS Fiddle DEMO

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


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


alert("Red bg set ");
});

There is no event raised when a class changes. The alternative is to manually raise an event when you programatically change the class:

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


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

UPDATE - 2015

This question seems to be gathering some visitors, so here is an update with an approach which can be used without having to modify existing code using the new MutationObserver:

var $div = $("#foo");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var attributeValue = $(mutation.target).prop(mutation.attributeName);
console.log("Class attribute changed to:", attributeValue);
});
});


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


$div.addClass('red');
.red {
color: #C00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="foo" class="bar">#foo.bar</div>

Be aware that the MutationObserver is only available for newer browsers, specifically Chrome 26, FF 14, IE 11, Opera 15 and Safari 6. See MDN for more details. If you need to support legacy browsers then you will need to use the method I outlined in my first example.


UPDATE - 2022

Here's an implementation of the above wrapped in to a jQuery extension method:

// extension method:
$.fn.classChange = function(cb) {
return $(this).each((_, el) => {
new MutationObserver(mutations => {
mutations.forEach(mutation => cb && cb(mutation.target, $(mutation.target).prop(mutation.attributeName)));
}).observe(el, {
attributes: true,
attributeFilter: ['class'] // only listen for class attribute changes
});
});
}


// usage:
const $foo = $("#foo").classChange((el, newClass) => console.log(`#${el.id} had its class updated to: ${newClass}`));
const $fizz = $("#fizz").classChange((el, newClass) => console.log(`#${el.id} had its class updated to: ${newClass}`));


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


.green {
color: #0C0;
}


.dark-bg {
background-color: #666;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<button id="trigger">Change classes</button>
<div id="foo" class="bar red">#foo.bar</div>
<div id="fizz" class="buzz">#fizz.buzz</div>

You could replace the original jQuery addClass and removeClass functions with your own that would call the original functions and then trigger a custom event. (Using a self-invoking anonymous function to contain the original function reference)

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

Then the rest of your code would be as simple as you'd expect.

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

Update:

JS Fiddle Demo

This approach does make the assumption that the classes will only be changed via the jQuery addClass and removeClass methods. If classes are modified in other ways (such as direct manipulation of the class attribute through the DOM element) use of something like MutationObservers as explained in the accepted answer here would be necessary.

Also as a couple improvements to these methods:

  • Trigger an event for each class being added (classAdded) or removed (classRemoved) with the specific class passed as an argument to the callback function and only triggered if the particular class was actually added (not present previously) or removed (was present previously)

  • Only trigger classChanged if any classes are actually changed

      (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
    }
    });
    if( 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);
    }
    });
    if( prevClasses != this.getAttribute('class') ) $this.trigger('classChanged');
    });
    return this;
    }
    })($.fn.removeClass);
    

With these replacement functions you can then handle any class changed via classChanged or specific classes being added or removed by checking the argument to the callback function:

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