我想要这样的东西:
$('#myDiv').bind('class "submission ok" added'){
alert('class "submission ok" has been added');
});
类更改时不会引发任何事件。另一种方法是在以编程方式更改类时手动引发事件:
$someElement.on('event', function() {
$('#myDiv').addClass('submission-ok').trigger('classChange');
});
// in another js file, far, far away
$('#myDiv').on('classChange', function() {
// do stuff
});
更新 - 2015
这个问题似乎吸引了一些访问者,所以这里有一个更新的方法,无需使用新的
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>
请注意,
MutationObserver
仅适用于较新的浏览器,特别是 Chrome 26、FF 14、IE 11、Opera 15 和 Safari 6。有关更多详细信息,请参阅 MDN。如果您需要支持旧版浏览器,那么您将需要使用我在第一个示例中概述的方法。
更新 - 2022 年
这是封装在 jQuery 扩展方法中的上述实现:
// extension method:
$.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'] // only listen for class attribute changes
});
});
}
// usage:
const $foo = $("#foo").onClassChange((el, newClass) => console.log(`#${el.id} had its class updated to: ${newClass}`));
const $fizz = $("#fizz").onClassChange((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>
您可以用自己的函数替换原始的 jQuery addClass 和 removeClass 函数,这些函数将调用原始函数,然后触发自定义事件。 (使用自调用匿名函数来包含原始函数引用)
(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);
那么您的其余代码将如您所期望的那样简单。
$(selector).on('classChanged', function(){ /*...*/ });
更新:
这种方法确实假设类只能通过 jQuery addClass 和 removeClass 方法更改。如果以其他方式修改类(例如通过 DOM 元素直接操作类属性),则需要使用类似
MutationObserver
的内容,如此处接受的答案中所述。
还有对这些方法的一些改进:
触发添加 (classAdded
) 或删除 (
classRemoved
) 类的事件,并将特定类作为参数传递给回调函数,并且仅在实际添加特定类时触发(之前不存在) )或删除(之前存在)
classChanged
(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);
$(document).on('classAdded', '#myElement', function(event, className) {
if(className == "something") { /* do something */ }
});