CSS क्लास में फायरिंग की घटनाएँ jQuery में बदल जाती हैं


240

अगर jQuery का उपयोग करके CSS क्लास जोड़ी या बदली जाती है तो मैं किसी घटना को कैसे फायर कर सकता हूं? क्या CSS वर्ग के बदलने से jQuery change()ईवेंट में आग लग जाती है ?


8
7 साल बाद, आधुनिक ब्राउज़रों में MutationObservers के काफी व्यापक गोद लेने के साथ, यहां स्वीकार किए गए उत्तर को वास्तव में ब्रेंट होने के लिए अपडेट किया जाना चाहिए ।
joelmdev

यह आपकी मदद कर सकता है। stackoverflow.com/questions/2157963/…
PSR

जेसन के जवाब को पूरा करने में, मुझे यह पता चला: stackoverflow.com/a/19401707/1579667
बेंज ऑक्ट

जवाबों:


223

जब भी आप अपनी स्क्रिप्ट में एक क्लास बदलते हैं, तो आप triggerअपनी खुद की घटना को बढ़ाने के लिए उपयोग कर सकते हैं ।

$(this).addClass('someClass');
$(mySelector).trigger('cssClassChanged')
....
$(otherSelector).bind('cssClassChanged', data, function(){ do stuff });

लेकिन अन्यथा, नहीं, जब क्लास बदलती है तो किसी घटना को आग लगाने का कोई तरीका नहीं है। change()फ़ोकस के बाद केवल आग एक इनपुट छोड़ती है जिसका इनपुट बदल दिया गया है।

$(function() {
  var button = $('.clickme')
      , box = $('.box')
  ;
  
  button.on('click', function() { 
    box.removeClass('box');
    $(document).trigger('buttonClick');
  });
            
  $(document).on('buttonClick', function() {
    box.text('Clicked!');
  });
});
.box { background-color: red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="box">Hi</div>
<button class="clickme">Click me</button>

JQuery के ट्रिगर पर अधिक जानकारी


4
उस घटना को ट्रिगर करने के साथ सौदा क्या है जो तब एक फ़ंक्शन को कॉल करता है? फ़ंक्शन को ट्रिगर करने के बजाय सीधे कॉल क्यों नहीं किया जाता है?
रेम्बोएन 5

43
ट्रिगरिंग एक ऐसा तंत्र है जो कुछ तत्वों को किसी घटना को "सब्सक्राइब" करने की अनुमति देगा। इस तरह, जब घटना को ट्रिगर किया जाता है, तो वे घटनाएं एक ही बार में हो सकती हैं और अपनी संबंधित कार्यक्षमता चला सकती हैं। उदाहरण के लिए, अगर मेरे पास एक ऐसी वस्तु है जो लाल से नीली और तीन वस्तुओं के बदलने की प्रतीक्षा कर रही है, जब वह बदल जाती है, तो मैं केवल changeColorघटना को ट्रिगर कर सकता हूं , और उस घटना की सदस्यता लेने वाले सभी ऑब्जेक्ट तदनुसार प्रतिक्रिया कर सकते हैं।
जेसन

1
थोड़ा अजीब लगता है कि ओपी 'cssClassChanged' इवेंट सुनना चाहता है; निश्चित रूप से क्लास को कुछ अन्य 'एप्लीकेशन' इवेंट जैसे कि 'कोलोरांचर्ड' के परिणामस्वरूप जोड़ा गया था, जो ट्रिगर के साथ घोषणा करने के लिए अधिक समझ में आता है क्योंकि मैं कल्पना नहीं कर सकता कि क्यों कुछ विशेष रूप से एक क्लासनाम परिवर्तन में दिलचस्पी होगी, यह अधिक है ClassNameChange का परिणाम निश्चित रूप से?
riscarrott

यदि यह विशेष रूप से एक वर्गीय परिवर्तन था जो कि रुचि का था, तो मैं सजाने की कल्पना करता था jQuery.fn.addClass को ट्रिगर करने के लिए 'cssClassChanged' अधिक समझदार होगा @ @redred ने कहा
riscarrott

5
@riscarrott मैं ओपी के आवेदन को नहीं जानता। मैं उन्हें पब / उप की अवधारणा के साथ प्रस्तुत कर रहा हूं और वे इसे लागू कर सकते हैं, हालांकि वे इसे पसंद करेंगे। विवादित है कि दी गई जानकारी की मात्रा के साथ वास्तविक घटना का नाम मूर्खतापूर्ण होना चाहिए।
जेसन

140

IMHO बेहतर समाधान @ RamboNo5 और @ जेसन द्वारा दो उत्तरों को संयोजित करना है

मेरा मतलब है AddClass फ़ंक्शन को ओवरराइड करना और एक कस्टम ईवेंट जोड़ना cssClassChanged

// Create a closure
(function(){
    // Your base, I'm in it!
    var originalAddClassMethod = jQuery.fn.addClass;

    jQuery.fn.addClass = function(){
        // Execute the original method.
        var result = originalAddClassMethod.apply( this, arguments );

        // trigger a custom event
        jQuery(this).trigger('cssClassChanged');

        // return the original result
        return result;
    }
})();

// document ready function
$(function(){
    $("#YourExampleElementID").bind('cssClassChanged', function(){ 
        //do stuff here
    });
});

यह वास्तव में सबसे अच्छा दृष्टिकोण की तरह लगता है, लेकिन यद्यपि मैं केवल "#YourExampleElementID" घटना को बांधता हूं, ऐसा प्रतीत होता है कि सभी वर्ग परिवर्तन (अर्थात, मेरे पृष्ठ के किसी भी तत्व पर) इस हैंडलर द्वारा संभाला जाता है ... कोई विचार?
फिलिप कोर्रेया

यह मेरे लिए @FilipeCorreia ठीक काम करता है। आप अपने मामले की नकल के साथ एक jsfiddle प्रदान कर सकते हैं?
अर्श मिलानी

@ Goldentoa11 आपको कुछ शाम या सप्ताहांत का समय लेना चाहिए और एक विशिष्ट पगेलोड पर होने वाली हर चीज़ की निगरानी करनी चाहिए जो विज्ञापन का भारी उपयोग करती है। इस तरह की चीजें करने के लिए आपको कई बार लिपियों की मात्रा से उड़ा दिया जाएगा (कभी-कभी सबसे शानदार तरीके से असफल)। मैंने उन पृष्ठों को चलाया है जो DOMNodeInserted / DOMSubtreeModified घटनाओं को प्रति सेकंड फायर करते हैं $(), जब आप वास्तविक क्रिया शुरू करते हैं, तब तक सैकड़ों घटनाओं को पूरा करते हैं ।
L0j1k

आप संभवतः हटाने पर भी उसी घटना को ट्रिगर करने का समर्थन करना चाहते हैं
Darius

4
Arash, मुझे लगता है कि मुझे समझ में आया कि क्यों @FilipeCorreia इस दृष्टिकोण के साथ कुछ मुद्दों का सामना कर रहा था: यदि आप इस cssClassChangedघटना को एक तत्व से बांधते हैं , तो आपको पता होना चाहिए कि यह तब भी निकाल दिया जाएगा जब इसका बच्चा अपनी कक्षा बदल दे। इसलिए अगर उदाहरण के लिए आप उनके लिए इस घटना को आग नहीं देना चाहते हैं, तो बस $("#YourExampleElementID *").on('cssClassChanged', function(e) { e.stopPropagation(); });अपने बंधन के बाद कुछ ऐसा जोड़ें । वैसे भी, वास्तव में अच्छा समाधान, धन्यवाद!
टॉनिक्स

59

यदि आप वर्ग परिवर्तन का पता लगाना चाहते हैं, तो सबसे अच्छा तरीका म्यूटेशन ऑब्जर्वर का उपयोग करना है, जो आपको किसी भी विशेषता परिवर्तन पर पूर्ण नियंत्रण प्रदान करता है। हालाँकि आपको अपने आप को श्रोता को परिभाषित करने की आवश्यकता है, और इसे उस तत्व से जोड़ना होगा जो आप सुन रहे हैं। अच्छी बात यह है कि श्रोता के जुड़ने के बाद आपको मैन्युअल रूप से कुछ भी ट्रिगर करने की आवश्यकता नहीं है।

$(function() {
(function($) {
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

    $.fn.attrchange = function(callback) {
        if (MutationObserver) {
            var options = {
                subtree: false,
                attributes: true
            };

            var observer = new MutationObserver(function(mutations) {
                mutations.forEach(function(e) {
                    callback.call(e.target, e.attributeName);
                });
            });

            return this.each(function() {
                observer.observe(this, options);
            });

        }
    }
})(jQuery);

//Now you need to append event listener
$('body *').attrchange(function(attrName) {

    if(attrName=='class'){
            alert('class changed');
    }else if(attrName=='id'){
            alert('id changed');
    }else{
        //OTHER ATTR CHANGED
    }

});
});

इस उदाहरण में ईवेंट श्रोता को हर तत्व से जोड़ा जाता है, लेकिन आप नहीं चाहते कि ज्यादातर मामलों में (मेमोरी को बचाएं)। इस "attrchange" श्रोता को उस तत्व में शामिल करें जिसे आप निरीक्षण करना चाहते हैं।


1
ऐसा लगता है कि यह वही काम कर रहा है जो स्वीकृत उत्तर कर रहा है, लेकिन अधिक कोड के साथ, कुछ ब्राउज़रों पर असमर्थित, और कम लचीलेपन के साथ। इसका एकमात्र लाभ यह प्रतीत होता है कि यह पृष्ठ पर हर बार कुछ बदलावों को आग लगा देगा , जो आपके प्रदर्शन को पूरी तरह से नष्ट कर देगा ...
जेसन

10
उत्तर में आपका कथन गलत है @ जसन, यह वास्तव में ऐसा करने का तरीका है यदि आप मैन्युअल रूप से कोई ट्रिगर सक्रिय नहीं करना चाहते हैं, लेकिन स्वचालित रूप से सक्रिय है। यह न केवल लाभ है यह लाभ है, क्योंकि यह प्रश्न में पूछा गया था। दूसरा, यह सिर्फ एक उदाहरण था, और जैसा कि उदाहरण में कहा गया है कि यह ईवेंट श्रोता को हर तत्व को जोड़ने का सुझाव नहीं दिया गया है, लेकिन केवल उन तत्वों को जिन्हें आप सुनना चाहते हैं, इसलिए मुझे समझ नहीं आता कि यह प्रदर्शन को क्यों नष्ट करेगा। और आखिरी बात, यह भविष्य है, अधिकांश नवीनतम ब्राउज़र इसका समर्थन करते हैं, caniuse.com/#feat=mutationobserver .Please पुनर्विचार संपादित करें, यह सही तरीका है।
श्री Br

1
InsertionQ पुस्तकालय तुम्हें पकड़ डोम दिखा नोड्स अगर वे एक चयनकर्ता से मेल कर सकते हैं। इसका व्यापक ब्राउज़र समर्थन है क्योंकि यह उपयोग नहीं करता है DOMMutationObserver
डेन डैस्कलेस्कु

यह एक बेहतरीन उपाय है। किसी वर्ग को जोड़ने या हटाने पर कैनवास या एसवीजी एनिमेशन शुरू करने और रोकने के लिए विशेष रूप से। मेरे मामले में यह सुनिश्चित करने के लिए कि उन्हें स्क्रॉल से बाहर नहीं किया जा रहा है। मिठाई!
बीबीसिंगर

1
2019 के लिए, यह स्वीकृत उत्तर होना चाहिए। सभी प्रमुख ब्राउज़र अब म्यूटेशन ऑब्जर्वर का समर्थन करते हैं, और इस समाधान को मैन्युअल रूप से घटनाओं को आग लगाने या बुनियादी jQuery कार्यक्षमता को फिर से लिखने की आवश्यकता नहीं है।
sp00n

53

मैं आपको AddClass फ़ंक्शन को ओवरराइड करने का सुझाव दूंगा। आप इसे इस तरह से कर सकते हैं:

// Create a closure
(function(){
    // Your base, I'm in it!
    var originalAddClassMethod = jQuery.fn.addClass;

    jQuery.fn.addClass = function(){
        // Execute the original method.
        var result = originalAddClassMethod.apply( this, arguments );

        // call your function
        // this gets called everytime you use the addClass method
        myfunction();

        // return the original result
        return result;
    }
})();

// document ready function
$(function(){
    // do stuff
});

16
जेसन के $ (mySelector) .trigger ('cssClassChanged') के साथ संयोजन करना मेरे विचार से सबसे अच्छा तरीका होगा।
कियोस्कैंट

4
वहाँ एक प्लगइन है कि यह
उदारता

37
भविष्य के अनुचर को भ्रमित करने का एक शानदार तरीका लगता है।
रौफैमैटिक

1
मूल विधि का परिणाम वापस करने के लिए मत भूलना।
पेटा

1
संदर्भ के लिए, आप प्रॉक्सी पैटर्न का उपयोग कर रहे हैं en.wikipedia.org/wiki/Proxy_pattern
Darius

22

बस अवधारणा का एक प्रमाण:

कुछ एनोटेशन देखने और अद्यतित रहने के लिए जिस्ट को देखें:

https://gist.github.com/yckart/c893d7db0f49b1ea4dfb

(function ($) {
  var methods = ['addClass', 'toggleClass', 'removeClass'];

  $.each(methods, function (index, method) {
    var originalMethod = $.fn[method];

    $.fn[method] = function () {
      var oldClass = this[0].className;
      var result = originalMethod.apply(this, arguments);
      var newClass = this[0].className;

      this.trigger(method, [oldClass, newClass]);

      return result;
    };
  });
}(window.jQuery || window.Zepto));

उपयोग काफी सरल है, बस आप जिस नोड को देखना चाहते हैं उस पर एक नया लिस्टेंडर जोड़ें और आमतौर पर कक्षाओं में हेरफेर करें:

var $node = $('div')

// listen to class-manipulation
.on('addClass toggleClass removeClass', function (e, oldClass, newClass) {
  console.log('Changed from %s to %s due %s', oldClass, newClass, e.type);
})

// make some changes
.addClass('foo')
.removeClass('foo')
.toggleClass('foo');

इसने मेरे लिए काम किया, सिवाय इसके कि मैं पुराने या नए वर्ग को हटाने के तरीके के साथ नहीं पढ़ सका।
स्लैशडॉटिर

1
@slashdottir क्या आप एक बेला बना सकते हैं और समझा सकते हैं कि वास्तव में क्या काम नहीं करता है
यार्क

हाँ ... काम नहीं करता। TypeError: यह [0] «वापसी में अपरिभाषित है [इसे [0] .className;»
पेड्रो फरेरा

यह काम करता है लेकिन कभी-कभी (क्यों?), this[0]अपरिभाषित होता है ... बस लाइनों के अंत को निम्नलिखित असाइनमेंट के साथ var oldClassऔर var newClass= (this[0] ? this[0].className : "");
बदलें

9

नवीनतम jquery म्यूटेशन का उपयोग करना

var $target = jQuery(".required-entry");
            var observer = new MutationObserver(function(mutations) {
                mutations.forEach(function(mutation) {
                    if (mutation.attributeName === "class") {
                        var attributeValue = jQuery(mutation.target).prop(mutation.attributeName);
                        if (attributeValue.indexOf("search-class") >= 0){
                            // do what you want
                        }
                    }
                });
            });
            observer.observe($target[0],  {
                attributes: true
            });

// कोई भी कोड जो div div class class -entry को अपडेट करता है जो $ target.addClass ('सर्च-क्लास') जैसे $ लक्ष्य में है;


अच्छा समाधान, मैं इसका उपयोग कर रहा हूं। हालाँकि, मैं प्रतिक्रिया का उपयोग कर रहा हूं और समस्या यह है कि मैं हर बार एक पर्यवेक्षक जोड़ता हूं कि वेब तत्व वास्तव में उत्पन्न होता है। क्या यह देखने का कोई तरीका है कि क्या कोई पर्यवेक्षक पहले से मौजूद है?
मिकाइल मेयर

मुझे लगता है कि यह मूल्यह्रास कर दिया गया है और इसका उपयोग [लिंक] डेवलपर.
mozilla.org/en-US/docs/Web/JavaScript/Reference/… के

@ WebDude0482 MutationObserver.observe को नहीं हटाया गया क्योंकि यह "MutationObserver" का "इंस्टेंस मेथड" है। देखें developer.mozilla.org/en-US/docs/Web/API/MutationObserver
न्यू एवरेस्ट

8

change()जब CSS क्लास जोड़ी जाती है या हटा दी जाती है या परिभाषा बदल जाती है तो आग नहीं लगती है। यह उन परिस्थितियों में आग लगती है जैसे जब एक चुनिंदा बॉक्स मूल्य चुना जाता है या अचयनित होता है।

मुझे यकीन नहीं है कि अगर आपका मतलब है अगर CSS वर्ग की परिभाषा को बदल दिया जाए (जो प्रोग्रामेटिक रूप से किया जा सकता है लेकिन थकाऊ है और आमतौर पर अनुशंसित नहीं है) या यदि एक वर्ग जोड़ा जाता है या किसी तत्व को हटाया जाता है। इस मामले में मज़बूती से कब्जा करने का कोई तरीका नहीं है।

आप निश्चित रूप से इसके लिए अपनी स्वयं की घटना बना सकते हैं लेकिन इसे केवल सलाहकार के रूप में वर्णित किया जा सकता है । यह उस कोड को कैप्चर नहीं करेगा जो आपका नहीं है।

वैकल्पिक रूप से आप addClass()jQuery में (आदि) तरीकों को ओवरराइड / रिप्लेस कर सकते हैं लेकिन जब वेनिला जावास्क्रिप्ट के माध्यम से किया जाता है तो यह कैप्चर नहीं करेगा (हालांकि मुझे लगता है कि आप उन तरीकों को भी बदल सकते हैं)।


8

कस्टम इवेंट को ट्रिगर किए बिना एक और तरीका है

रिक स्ट्राल द्वारा एचटीएमएल तत्व सीएसएस परिवर्तन की निगरानी के लिए एक jQuery प्लग-इन

ऊपर से उद्धृत करना

वॉच प्लग-इन काम करता है। DOMAttrModified को FireFox में हुक करके, इंटरनेट एक्सप्लोरर में onPropertyChanged पर, या अन्य ब्राउज़रों के लिए परिवर्तनों का पता लगाने के लिए setInterval के साथ टाइमर का उपयोग करके। दुर्भाग्य से WebKit इस समय DOMAttrModified का लगातार समर्थन नहीं करता है इसलिए Safari और Chrome को वर्तमान में धीमे setInvval तंत्र का उपयोग करना होगा।


6

अच्छा प्रश्न। मैं बूटस्ट्रैप ड्रॉपडाउन मेनू का उपयोग कर रहा हूं, और बूटस्ट्रैप ड्रॉपडाउन के छिपे होने पर एक घटना को निष्पादित करने की आवश्यकता है। जब ड्रॉपडाउन खोला जाता है, तो "बटन-समूह" के एक वर्ग नाम के साथ युक्त डिव "ओपन" का एक वर्ग जोड़ता है; और बटन में ही "aria- विस्तारित" विशेषता सच है। जब ड्रॉपडाउन बंद हो जाता है, तो "ओपन" के उस वर्ग को युक्त डिव से हटा दिया जाता है, और एरिया-विस्तारित को सही से गलत में बदल दिया जाता है।

यह मुझे इस सवाल की ओर ले गया कि कैसे वर्ग परिवर्तन का पता लगाया जाए।

बूटस्ट्रैप के साथ, "ड्रॉपडाउन इवेंट" हैं जिन्हें पता लगाया जा सकता है। इस लिंक पर "ड्रॉपडाउन इवेंट्स" देखें। http://www.w3schools.com/bootstrap/bootstrap_ref_js_dropdown.asp

यहां बूटस्ट्रैप ड्रॉपडाउन पर इस घटना का उपयोग करने का एक त्वरित और गंदा उदाहरण है।

$(document).on('hidden.bs.dropdown', function(event) {
    console.log('closed');
});

अब मुझे एहसास हुआ कि यह पूछे जाने वाले सामान्य प्रश्न से अधिक विशिष्ट है। लेकिन मुझे लगता है कि बूटस्ट्रैप ड्रॉपडाउन के साथ एक खुली या बंद घटना का पता लगाने की कोशिश करने वाले अन्य डेवलपर्स को यह मददगार लगेगा। मेरी तरह, वे शुरू में एक तत्व वर्ग परिवर्तन का पता लगाने की कोशिश कर सकते हैं (जो स्पष्ट रूप से इतना सरल नहीं है)। धन्यवाद।


5

यदि आपको एक विशिष्ट ईवेंट को ट्रिगर करने की आवश्यकता है, तो आप 'classadded' नामक एक कस्टम ईवेंट को आग लगाने के लिए विधि addClass () को ओवरराइड कर सकते हैं।

यहाँ कैसे:

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

$('#myElement').on('classadded', function(ev, newClasses) {
    console.log(newClasses + ' added!');
    console.log(this);
    // Do stuff
    // ...
});

5

आप DOMSubtreeModified इवेंट को बाइंड कर सकते हैं। मैं यहां एक उदाहरण जोड़ता हूं:

एचटीएमएल

<div id="mutable" style="width:50px;height:50px;">sjdfhksfh<div>
<div>
  <button id="changeClass">Change Class</button>
</div>

जावास्क्रिप्ट

$(document).ready(function() {
  $('#changeClass').click(function() {
    $('#mutable').addClass("red");
  });

  $('#mutable').bind('DOMSubtreeModified', function(e) {
      alert('class changed');
  });
});

http://jsfiddle.net/hnCxK/13/


0

यदि आप जानते हैं कि किस घटना ने पहली बार कक्षा को बदल दिया है तो आप उसी घटना पर थोड़ी देरी और कक्षा के लिए जाँच कर सकते हैं। उदाहरण

//this is not the code you control
$('input').on('blur', function(){
    $(this).addClass('error');
    $(this).before("<div class='someClass'>Warning Error</div>");
});

//this is your code
$('input').on('blur', function(){
    var el= $(this);
    setTimeout(function(){
        if ($(el).hasClass('error')){ 
            $(el).removeClass('error');
            $(el).prev('.someClass').hide();
        }
    },1000);
});

http://jsfiddle.net/GuDCp/3/


0
var timeout_check_change_class;

function check_change_class( selector )
{
    $(selector).each(function(index, el) {
        var data_old_class = $(el).attr('data-old-class');
        if (typeof data_old_class !== typeof undefined && data_old_class !== false) 
        {

            if( data_old_class != $(el).attr('class') )
            {
                $(el).trigger('change_class');
            }
        }

        $(el).attr('data-old-class', $(el).attr('class') );

    });

    clearTimeout( timeout_check_change_class );
    timeout_check_change_class = setTimeout(check_change_class, 10, selector);
}
check_change_class( '.breakpoint' );


$('.breakpoint').on('change_class', function(event) {
    console.log('haschange');
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.