JQuery kullanarak sınıf değişikliğinde bir olay nasıl tetiklenir?


91

Şunun gibi bir şeye sahip olmak istiyorum:

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

Yanıtlar:


172

Bir sınıf değiştiğinde ortaya çıkan bir olay yoktur. Alternatif, sınıfı programatik olarak değiştirdiğinizde bir olayı manuel olarak yükseltmektir:

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

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

GÜNCELLEME

Bu soru, bazı ziyaretçileri topluyor gibi görünüyor, bu nedenle, yenisini kullanarak mevcut kodu değiştirmek zorunda kalmadan kullanılabilecek bir yaklaşımla güncelleme 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>

Unutmayın MutationObserverözellikle Krom 26 FF 14, IE 11 yeni tarayıcılarda için kullanılabilir, Opera 15 ve Safari 6. Bkz MDN fazla ayrıntı için. Eski tarayıcıları desteklemeniz gerekiyorsa, ilk örneğimde özetlediğim yöntemi kullanmanız gerekecektir.


Bu cevabı tamamladıktan sonra şunu buldum: stackoverflow.com/a/1950052/1579667
Benj

1
@Benj Bu, orijinal cevabımla aynı (yani kullanarak trigger()), ancak kullanımı nedeniyle çok eski olduğuna dikkat edin bind(). Yine de her şeyi nasıl 'tamamladığından' emin değilim
Rory McCrossan

Benim durumumda, bir dom düğümünün MutationObserverbenim için çalıştığı belirli bir sınıf olduğunda bir olayı
Mario


20

Orijinal jQuery addClass ve removeClass işlevlerini, orijinal işlevleri çağıran ve ardından özel bir olayı tetikleyen kendi işlevlerinizle değiştirebilirsiniz. (Orijinal işlev referansını içermek için kendi kendini çağıran bir anonim işlevi kullanma)

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

O zaman kodunuzun geri kalanı beklediğiniz kadar basit olacaktır.

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

Güncelleme:

Bu yaklaşım, sınıfların yalnızca jQuery addClass ve removeClass yöntemleri aracılığıyla değiştirileceği varsayımını yapar. Sınıflar başka şekillerde değiştirilirse (sınıf özniteliğinin DOM öğesi aracılığıyla doğrudan işlenmesi gibi MutationObserver), burada kabul edilen yanıtta açıklandığı gibi s gibi bir şeyin kullanılması gerekli olacaktır.

Ayrıca bu yöntemlerde birkaç iyileştirme olarak:

  • Geri çağırma işlevine bağımsız değişken olarak iletilen belirli sınıf ile eklenen ( ) veya kaldırılan ( ) her sınıf için bir olay tetikleyin ve yalnızca belirli bir sınıf gerçekten eklendiyse (daha önce mevcut değilse) veya kaldırıldıysa (daha önce mevcuttu)classAddedclassRemoved
  • Yalnızca classChangedherhangi bir sınıf gerçekten değiştirilirse tetikleyin

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

Bu değiştirme işlevleriyle, geri çağrı işlevine argümanı kontrol ederek, classChanged aracılığıyla değiştirilen herhangi bir sınıfı veya eklenen veya kaldırılan belirli sınıfları işleyebilirsiniz:

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

1
Bu cezayı çalışır ancak "kodunun geri kalanı" olay işleyicisi yeni elemanlar bağlanmaya imkan vermek için hedef seçicinin devredilebilir edilmelidir: $(parent_selector).on('classChanged', target_selector, function(){ /*...*/ });. Dinamik olarak oluşturduğum unsurların neden işleyiciyi ateşlemediğini anlamam biraz zaman aldı. See learn.jquery.com/events/event-delegation
Timm


2

bunun gibi bir şey kullanabilirsiniz:

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

$(Selector).trigger('ClassChanged')

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

ancak aksi takdirde hayır, sınıf değiştiğinde bir olayı tetikleyecek önceden tanımlanmış bir işlev yoktur.

Tetikleyiciler hakkında daha fazlasını buradan okuyun


1
Olayın işleyicisi, olayı tetikleyen öğe ile aynı olmalıdır. $ (this) .addClass ('birSınıf'); $ (Selector) .trigger ('ClassChanged') // Aynı Seçici olmalı $ (Selector) .bind ('ClassChanged', data, function () {// stuff});
Meko Perez Estevez

3
Görünüşe göre buradan kopyaladınız, evet ise o zaman iyi bağlantı da
sağlarsanız
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.