Bir "stil değişikliği" etkinliği dinlemek mümkün müdür?


206

JQuery'de herhangi bir stil değişikliğine bağlanabilecek bir olay dinleyicisi oluşturmak mümkün müdür? Örneğin, bir öğe boyutları değiştirdiğinde ya da yapabileceğim stil özniteliğindeki herhangi bir değişiklik olduğunda "bir şey" yapmak istiyorsanız:

$('div').bind('style', function() {
    console.log($(this).css('height'));
});

$('div').height(100); // yields '100'

Gerçekten faydalı olurdu.

Herhangi bir fikir?

GÜNCELLEME

Bunu kendim cevapladığım için özür dilerim, ama bir başkasına uyabilecek düzgün bir çözüm yazdım:

(function() {
    var ev = new $.Event('style'),
        orig = $.fn.css;
    $.fn.css = function() {
        $(this).trigger(ev);
        return orig.apply(this, arguments);
    }
})();

Bu, dahili prototy..cs yöntemini geçici olarak geçersiz kılar ve sonunda bir tetikleyici ile yeniden tanımlar. Yani şu şekilde çalışır:

$('p').bind('style', function(e) {
    console.log( $(this).attr('style') );
});

$('p').width(100);
$('p').css('color','red');

Evet, güzel bir çözüm, ama gerçek bir uygulamada, bu çok fazla kaynak alabilir ve hatta tarayıcı kullanıcının etkileşimlerine ayak uydurmak için yavaş görünmesini sağlayabilir. Durumun bu olup olmadığını bilmek isterim.
pixeline

1
@pixeline: Çok daha yavaş olması gerektiğini göremiyorum. jQuery yine de css prototip çağırıyor, ben sadece bir tetikleyici ekliyorum. Yani temelde sadece bir ekstra yöntem çağrısı.
David Hellsing

Anlıyorum: sadece bir uygulama ile etkileşen bir kullanıcının akışında, css () çok zaman denir gibi görünüyor. Bu tetikleyici ile ne yaptığınıza bağlı olarak (sadece bir konsol günlüğü ise, sanırım güvendesiniz), bu sorunlar yaratabilir. Sadece merak ediyorum. Uygulamaya da bağlıdır. Şahsen eşyalarımda çok fazla görsel geri bildirim yapmaya eğilimliyim.
pixeline

Mevcut jquery css çağrılarıyla çalışmasını sağlamak için birkaç şey daha var: 1) öğeyi yeni css işlevinizden geri döndürmek isteyeceksiniz, yoksa akıcı stil css çağrılarını bozacaktır. Örneğin. $ ('p'). css ('ekran', 'blok'). css ('renk', 'siyah'); 2) bir özellik değeri çağrısı ise (örn. 'obj.css (' height ');') orijinal işlevin dönüş değerini döndürmek istersiniz - Bunu argümanlar listesinin çünkü fonksiyon sadece bir argüman içerir.
theringostarrs

1
Stil yaklaşımının kendisi kaldırıldığında da çalışan bu yaklaşımın daha sağlam bir versiyonunu yaptım . Bu şekilde kaldırılan her stil için bir 'stil' olayı atar. gist.github.com/bbottema/426810c21ae6174148d4
Benny Bottema

Yanıtlar:


19

JQuery açık kaynak olduğundan, cssher çağrıldığında (jQuery nesnesini geçirerek) seçtiğiniz bir işlevi çağırmak için işlevi düzenleyebilirsiniz tahmin ediyorum . Tabii ki, CSS özelliklerini ayarlamak için dahili olarak kullandığı başka bir şey olmadığından emin olmak için jQuery kodunu taramak isteyeceksiniz. İdeal olarak, jQuery kütüphanesinin kendisine müdahale etmemesi için jQuery için ayrı bir eklenti yazmak istersiniz, ancak bunun projeniz için uygun olup olmadığına karar vermeniz gerekir.


1
Ancak bu durumda style özelliğini DOM işlevleriyle doğrudan ayarlarsam ne olur?
Jaime Hablutzel

İşte bu çözümün tam bir örneği: gist.github.com/bbottema/426810c21ae6174148d4
Benny Bottema 18:15

272

Soru sorulduğundan beri işler biraz ilerledi - artık bir elemanın 'stil' özelliğindeki değişiklikleri tespit etmek için bir MutationObserver kullanmak mümkün , jQuery gerekli değil:

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutationRecord) {
        console.log('style changed!');
    });    
});

var target = document.getElementById('myId');
observer.observe(target, { attributes : true, attributeFilter : ['style'] });

Geri arama işlevine iletilen bağımsız değişken , eski ve yeni stil değerlerini elde etmenizi sağlayan bir MutationRecord nesnesidir.

IE 11+ dahil modern tarayıcılarda destek iyidir .


19
Bunun, sınıf değişikliği veya @mediadeğişikliğinin bir sonucu olarak stil değiştiğinde değil, yalnızca satır içi stillerle çalıştığını unutmayın .
fregante

2
@ bfred.it sadece bunu başarmak için bir fikriniz olur mu? Bir sınıfın css kuralları bir öğeye uygulandıktan sonra bazı js çalıştırmak istiyorum.
Kragalon

Sen kullanabilirsiniz getComputedStyleile setIntervalancak web sitenizin çok yavaşlatmak olacaktır.
fregante

Not: MutationObserver, caniuse'un söylediklerine rağmen aslında Android 4.4'ün tüm sürümlerinde çalışmaz.
James Gould

Metin alanının genişliği 300 pikselden fazla uzatıldığında, metin alanının arka plan rengini maviye değiştirme örneği için bu twiddle bakın. jsfiddle.net/RyanNerd/y2q8wuf0 (ne yazık ki FF'de senaryoyu HTMLElement.style.prop = "value"
asan

18

Etkinlik nesnenizin bildirimi yeni css işlevinizin içinde olmalıdır. Aksi takdirde, olay yalnızca bir kez başlatılabilir.

(function() {
    orig = $.fn.css;
    $.fn.css = function() {
        var ev = new $.Event('style');
        orig.apply(this, arguments);
        $(this).trigger(ev);
    }
})();

Harika teşekkür ederim. Bazı insanlar orijinal kaynağı değiştirdiğini söyler, ancak uzantınız en iyisidir. Bazı problemlerim vardı ama sonunda işe yarıyor.
ccsakuweb

Bu kodu yürüttükten sonra sürekli tetikler ve hatta gerekli sonucu elde etmez.
smkrn110

13

Bence Mike'dan olayınızı başlatamazsanız en iyi cevap kodunuzdan değil. Ama kullandığımda bazı hatalar alıyorum. Bu yüzden size kullandığım kodu göstermek için yeni bir cevap yazıyorum.

Uzantı

// Extends functionality of ".css()"
// This could be renamed if you'd like (i.e. "$.fn.cssWithListener = func ...")
(function() {
    orig = $.fn.css;
    $.fn.css = function() {
        var result = orig.apply(this, arguments);
        $(this).trigger('stylechanged');
        return result;
    }
})();

kullanım

// Add listener
$('element').on('stylechanged', function () {
    console.log('css changed');
});

// Perform change
$('element').css('background', 'red');

Hata var çünkü var ev = new $ .Event ('style'); HtmlDiv'de stil gibi bir şey tanımlanmadı .. Onu kaldırdım ve şimdi $ (this) .trigger ("stylechanged") 'i başlattım. Başka bir sorun, Mike $ (css, ..) sonuç döndürmedi sonra bazı durumlarda sorun yapabilir. Bu yüzden sonucu alıp iade ediyorum. Şimdi çalışır ^^ Her css değişikliği bazı olayları değiştirmek ve bir olay tetikleyemez içerir.


Çok yararlı ve zeki
dgo

5

Diğerlerinin önerdiği gibi, öğenin stilini değiştiren herhangi bir kod üzerinde kontrolünüz varsa, öğenin yüksekliğini değiştirdiğinizde özel bir olayı tetikleyebilirsiniz:

$('#blah').bind('height-changed',function(){...});
...
$('#blah').css({height:'100px'});
$('#blah').trigger('height-changed');

Aksi halde, kaynak yoğun olmasına rağmen, öğenin yüksekliğindeki değişiklikleri düzenli olarak kontrol etmek için bir zamanlayıcı ayarlayabilirsiniz ...


Bu, stilleri değiştiren koda erişebiliyorsa, bu gerçekten çok temiz bir çözümdür.
Umair Hafeez

2

JQuery veya java komut dosyasında stil değişikliği olayı için dahili destek yoktur. Ancak jQuery, özel etkinlik oluşturmayı ve dinlemeyi destekler, ancak her değişiklik olduğunda bunu kendiniz tetiklemek için bir yolunuz olmalıdır. Yani tam bir çözüm olmayacak.


2

Jquery eklentisini deneyebilirsiniz, css değiştiğinde ve kullanımı kolay olduğunda olayları tetikler

http://meetselva.github.io/#gist-section-attrchangeExtension
 $([selector]).attrchange({
  trackValues: true, 
  callback: function (e) {
    //console.log( '<p>Attribute <b>' + e.attributeName +'</b> changed from <b>' + e.oldValue +'</b> to <b>' + e.newValue +'</b></p>');
    //event.attributeName - Attribute Name
    //event.oldValue - Prev Value
    //event.newValue - New Value
  }
});

1

İlginç soru. Sorun, height () öğesinin geri aramayı kabul etmemesi, bu nedenle geri aramayı tetikleyemezsiniz. Yüksekliği ayarlamak için animate () veya css () öğesini kullanın ve ardından geri aramada özel etkinliği tetikleyin. İşte kavramın kanıtı olarak animate (), test edilmiş ve works ( demo ) kullanan bir örnek :

$('#test').bind('style', function() {
    alert($(this).css('height'));
});

$('#test').animate({height: 100},function(){
$(this).trigger('style');
}); 

8
Üzgünüm, ama bu ne kanıtladı? Sen trigger()olayı manuel olarak. Ben bir stil özniteliği değiştirildiğinde OP bazı otomatik tetiklenen olay sonra olduğunu düşünüyorum.
JPot

@JPot, height özelliğinin değiştirildiğinde olayları atmadığını gösteriyor.
AnthonyJClink

1

Sadece @David'in çözümünü yukarıdan eklemek ve resmileştirmek:

JQuery işlevlerinin zincirlenebilir olduğunu ve birden fazla çağrının birbiri ardına çağrılabilmesi için "bu" ifadesini döndürdüğünü unutmayın (örn. $container.css("overflow", "hidden").css("outline", 0);).

Geliştirilmiş kod şöyle olmalıdır:

(function() {
    var ev = new $.Event('style'),
        orig = $.fn.css;
    $.fn.css = function() {
        var ret = orig.apply(this, arguments);
        $(this).trigger(ev);
        return ret; // must include this
    }
})();

0

JQuery cssHooks hakkında nasıl?

Belki soruyu anlamıyorum, ama aradığınız şey işlev cssHooksdeğiştirmeden kolayca yapılabilir css().

belgelerden kopyala:

(function( $ ) {

// First, check to see if cssHooks are supported
if ( !$.cssHooks ) {
  // If not, output an error message
  throw( new Error( "jQuery 1.4.3 or above is required for this plugin to work" ) );
}

// Wrap in a document ready call, because jQuery writes
// cssHooks at this time and will blow away your functions
// if they exist.
$(function () {
  $.cssHooks[ "someCSSProp" ] = {
    get: function( elem, computed, extra ) {
      // Handle getting the CSS property
    },
    set: function( elem, value ) {
      // Handle setting the CSS value
    }
  };
});

})( jQuery ); 

https://api.jquery.com/jQuery.cssHooks/


-1

Aynı problemim vardı, bu yüzden yazdım. Oldukça iyi çalışıyor. Bazı CSS geçişleriyle karıştırırsanız harika görünüyor.

function toggle_visibility(id) {
   var e = document.getElementById("mjwelcome");
   if(e.style.height == '')
      e.style.height = '0px';
   else
      e.style.height = '';
}
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.