JQuery के साथ बाध्य घटनाओं को कैसे ऑर्डर करें


164

बता दें कि मेरे पास एक वेब ऐप है जिसमें एक पेज है जिसमें 4 स्क्रिप्ट ब्लॉक हो सकते हैं - जो स्क्रिप्ट मैं लिखता हूं, वह उन ब्लॉकों में से एक में मिल सकती है, लेकिन मुझे नहीं पता कि कौन सा नियंत्रक द्वारा नियंत्रित किया जाता है।

मैं कुछ onclickघटनाओं को एक बटन से बांधता हूं , लेकिन मुझे लगता है कि वे कभी-कभी ऐसे क्रम में निष्पादित होते हैं जिसकी मुझे उम्मीद नहीं थी।

क्या आदेश सुनिश्चित करने का कोई तरीका है, या आपने अतीत में इस समस्या को कैसे संभाला है?


1
अपने कॉलबैक को एक कॉलबैक ऑब्जेक्ट में जोड़ें और जब आप उन्हें फायर करना चाहते हैं तो आप उन सभी को एक ही बार में आग लगा सकते हैं और वे जोड़े गए क्रम में चलेंगे। api.jquery.com/jQuery.Callbacks
Tyddlywink

जवाबों:


28

मैं इस तरह की प्रक्रिया को सामान्य बनाने के लिए युगों से प्रयासरत था, लेकिन मेरे मामले में मैं केवल श्रृंखला के पहले ईवेंट श्रोता के आदेश से संबंधित था।

यदि यह किसी काम का है, तो यहां मेरा jQuery प्लगइन है जो एक इवेंट श्रोता को बांधता है जो हमेशा किसी अन्य से पहले ट्रिगर होता है:

** jQuery के परिवर्तन के साथ अद्यतन इनलाइन (धन्यवाद Toskan) **

(function($) {
    $.fn.bindFirst = function(/*String*/ eventType, /*[Object])*/ eventData, /*Function*/ handler) {
        var indexOfDot = eventType.indexOf(".");
        var eventNameSpace = indexOfDot > 0 ? eventType.substring(indexOfDot) : "";

        eventType = indexOfDot > 0 ? eventType.substring(0, indexOfDot) : eventType;
        handler = handler == undefined ? eventData : handler;
        eventData = typeof eventData == "function" ? {} : eventData;

        return this.each(function() {
            var $this = $(this);
            var currentAttrListener = this["on" + eventType];

            if (currentAttrListener) {
                $this.bind(eventType, function(e) {
                    return currentAttrListener(e.originalEvent); 
                });

                this["on" + eventType] = null;
            }

            $this.bind(eventType + eventNameSpace, eventData, handler);

            var allEvents = $this.data("events") || $._data($this[0], "events");
            var typeEvents = allEvents[eventType];
            var newEvent = typeEvents.pop();
            typeEvents.unshift(newEvent);
        });
    };
})(jQuery);

ध्यान देने योग्य बातें:

  • यह पूरी तरह से परीक्षण नहीं किया गया है।
  • यह jQuery के ढांचे के परिवर्तन (केवल 1.5.2 के साथ परीक्षण) के आंतरिक पर निर्भर करता है।
  • यह आवश्यक रूप से इवेंट श्रोताओं से पहले ट्रिगर नहीं होगा जो कि स्रोत तत्व की विशेषता के रूप में या jQuery बाइंड () और अन्य संबंधित कार्यों का उपयोग करने के अलावा किसी भी तरह से बाध्य हैं।

यह ध्यान रखना महत्वपूर्ण है कि यह केवल उन घटनाओं के लिए भी काम करता है जिन्हें jQuery के माध्यम से जोड़ा गया था।
ग्रिन

1
यह किसी भी अधिक काम नहीं करता है क्योंकि यह उपयोग करता है this.data("events"), यहां देखें stackoverflow.com/questions/12214654/…
Toskan

4
इसी तरह का एक फ़ंक्शन है जिसे यहाँ jQuery 1.8 के लिए अपडेट किया गया है: stackoverflow.com/a/2641047/850782
एपिकवॉयज

136

यदि आदेश महत्वपूर्ण है, तो आप अपनी स्वयं की घटनाओं को बना सकते हैं और कॉलबैक को आग में बांध सकते हैं जब उन घटनाओं को अन्य कॉलबैक द्वारा ट्रिगर किया जाता है।

$('#mydiv').click(function(e) {
    // maniplate #mydiv ...
    $('#mydiv').trigger('mydiv-manipulated');
});

$('#mydiv').bind('mydiv-manipulated', function(e) {
    // do more stuff now that #mydiv has been manipulated
    return;
});

कम से कम ऐसा कुछ।


23
क्या होगा अगर हम अपने बाइंड कोड से पहले किसी बिंदु पर परिभाषित कॉलबैक के लिए क्लिक इवेंट के प्रचार को रोकना चाहते हैं।
विनीलियोस

2
क्या मैं पूछ सकता हूं कि यह अस्वीकार्य क्यों था? वर्तमान में स्वीकृत उत्तर मेरे उत्तर को सर्वोत्तम विधि के रूप में उद्धृत करता है, इसलिए मैं एक प्रकार का भ्रमित हूं। :-)
dowski

यह mkoryak के मामले के लिए काम करता है, लेकिन अगर एक ही घटना को कई बार नहीं कहा जा रहा है। मेरे पास एक समान मुद्दा है, जहां एक एकल कीस्ट्रोक $ (विंडो) .scroll () कई बार, रिवर्स ऑर्डर में ट्रिगर होता है ।
19 अगस्त को kxsong

37

Dowski का तरीका अच्छा है अगर आपके सभी कॉलबैक हमेशा मौजूद रहेंगे और आप एक दूसरे पर निर्भर होने से खुश हैं।

यदि आप चाहते हैं कि कॉलबैक एक-दूसरे से स्वतंत्र हो, हालांकि, आप बुदबुदाहट का लाभ उठा सकते हैं और बाद की घटनाओं को मूल तत्वों के प्रतिनिधि के रूप में संलग्न कर सकते हैं। एक मूल तत्वों पर हैंडलर को तत्व पर हैंडलर के बाद ट्रिगर किया जाएगा, दस्तावेज़ पर सही जारी रहेगा। यह काफी अच्छा के रूप में आप का उपयोग कर सकते है event.stopPropagation(), event.preventDefault(), आदि संचालकों छोड़ सकते हैं और रद्द करने या कार्रवाई रद्द किया जाना निरस्त करने के लिए।

$( '#mybutton' ).click( function(e) { 
    // Do stuff first
} );

$( '#mybutton' ).click( function(e) { 
    // Do other stuff first
} );

$( document ).delegate( '#mybutton', 'click', function(e) {
    // Do stuff last
} );

या, यदि आपको यह पसंद नहीं है, तो आप किसी घटना को अंतिम बाध्य करने के लिए बाध्य करने के लिए Nick Leaches bindLast प्लगइन का उपयोग कर सकते हैं: https://github.com/nickyleach/jQuery.bindLast

या, यदि आप jQuery 1.5 का उपयोग कर रहे हैं, तो आप संभावित रूप से नए आस्थगित ऑब्जेक्ट के साथ कुछ चतुर भी कर सकते हैं।


6
.delegateकिसी भी अधिक उपयोग नहीं किया जाता है और आपको अब उपयोग करना चाहिए .on, फिर भी मुझे नहीं पता कि आप उसी व्यवहार के साथ कैसे पहुंच सकते हैंon
eric.itzhak

प्लग इन को ठीक करना होगा क्योंकि यह यहाँ और अधिक देखने के लिए काम नहीं करता है: stackoverflow.com/questions/12214654/…
Toskan

@ eric.itzhak बनाने के लिए .on () पुराने .delegate () की तरह व्यवहार करें, बस इसे एक चयनकर्ता प्रदान करें। विवरण यहाँ api.jquery.com/delegate
सैम कौफमैन

यदि आप बुदबुदाहट का लाभ उठाना चाहते हैं, तो मुझे लगता है कि घटना को प्रतिनिधि के बजाय प्रत्यक्ष होने की आवश्यकता है । api.jquery.com/on/#direct-and-delegated-events
Ryne Everett

15

बाध्य कॉलबैक को जिस क्रम में बुलाया जाता है वह प्रत्येक jQuery ऑब्जेक्ट के इवेंट डेटा द्वारा प्रबंधित किया जाता है। कोई कार्य नहीं हैं (जो मुझे पता है) जो आपको सीधे उस डेटा को देखने और हेरफेर करने की अनुमति देते हैं, आप केवल बाइंड () और अनबाइंड () या (किसी भी समान सहायक फ़ंक्शन) का उपयोग कर सकते हैं।

Dowski की विधि सबसे अच्छी है, आपको "वास्तविक" घटना के लिए बाध्य "पहले" कॉलबैक के साथ, कस्टम घटनाओं के क्रम के लिए बाध्य करने के लिए विभिन्न बाध्य कॉलबैक को संशोधित करना चाहिए। इस तरह, कोई फर्क नहीं पड़ता कि वे किस क्रम में बंधे हैं, यह क्रम सही तरीके से निष्पादित होगा।

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

यह अच्छा होगा यदि jQuery ने आपको किसी ऑब्जेक्ट के ईवेंट डेटा में बाध्य घटनाओं के क्रम को बदलने की अनुमति दी है, लेकिन संभव नहीं लगता है कि jQuery कोर में हुक करने के लिए कुछ कोड लिखे बिना। और संभवतः इसे अनुमति देने के निहितार्थ हैं जो मैंने नहीं सोचा था, इसलिए शायद यह एक जानबूझकर चूक है।


12
jquery के द्वारा एक तत्व से बंधे सभी घटनाओं को देखने के लिए var allvvents = $ .data (यह, "ईवेंट");
redsquare

9

कृपया ध्यान दें कि jQuery ब्रह्मांड में इसे संस्करण 1.8 के अनुसार अलग-अलग लागू किया जाना चाहिए। निम्नलिखित रिलीज नोट jQuery के ब्लॉग से है:

.data ("ईवेंट्स"): jQuery प्रत्येक इवेंट पर अपने डेटा-संबंधित इवेंट (प्रतीक्षा के लिए) ईवेंट संबंधित डेटा संग्रहीत करता है। यह एक आंतरिक डेटा संरचना है इसलिए 1.8 में इसे उपयोगकर्ता डेटा नाम स्थान से हटा दिया जाएगा ताकि यह उसी नाम की वस्तुओं के साथ संघर्ष न करे। jQuery का ईवेंट डेटा अभी भी jQuery._data (तत्व, "ईवेंट") के माध्यम से एक्सेस किया जा सकता है

हमारे पास उस क्रम का पूर्ण नियंत्रण है जिसमें हैंडलर jQuery ब्रह्मांड में निष्पादित करेंगे । रिकू इसे ऊपर इंगित करता है। ऐसा नहीं लगता कि उनके जवाब से उन्हें बहुत प्यार मिला, लेकिन यह तकनीक बहुत आसान है। उदाहरण के लिए, किसी भी समय आपको अपने स्वयं के हैंडलर को लाइब्रेरी विजेट में कुछ हैंडलर से पहले निष्पादित करने की आवश्यकता होती है, या आपको सशर्त रूप से विजेट के हैंडलर को कॉल रद्द करने की आवश्यकता है:

$("button").click(function(e){
    if(bSomeConditional)
       e.stopImmediatePropagation();//Don't execute the widget's handler
}).each(function () {
    var aClickListeners = $._data(this, "events").click;
    aClickListeners.reverse();
});

7

बस सामान्य रूप से हैंडलर बांधें और फिर चलाएं:

element.data('events').action.reverse();

उदाहरण के लिए:

$('#mydiv').data('events').click.reverse();

2
काम नहीं करता है, लेकिन यह $._data(element, 'events')[name].reverse()काम करता है
Attenzione

7
function bindFirst(owner, event, handler) {
    owner.unbind(event, handler);
    owner.bind(event, handler);

    var events = owner.data('events')[event];
    events.unshift(events.pop());

    owner.data('events')[event] = events;
}

3

आप कुछ इस तरह की कोशिश कर सकते हैं:

/**
  * Guarantee that a event handler allways be the last to execute
  * @param owner The jquery object with any others events handlers $(selector)
  * @param event The event descriptor like 'click'
  * @param handler The event handler to be executed allways at the end.
**/
function bindAtTheEnd(owner,event,handler){
    var aux=function(){owner.unbind(event,handler);owner.bind(event,handler);};
    bindAtTheStart(owner,event,aux,true);

}
/**
  * Bind a event handler at the start of all others events handlers.
  * @param owner Jquery object with any others events handlers $(selector);
  * @param event The event descriptor for example 'click';
  * @param handler The event handler to bind at the start.
  * @param one If the function only be executed once.
**/
function bindAtTheStart(owner,event,handler,one){
    var eventos,index;
    var handlers=new Array();
    owner.unbind(event,handler);
    eventos=owner.data("events")[event];
    for(index=0;index<eventos.length;index+=1){
        handlers[index]=eventos[index];
    }
    owner.unbind(event);
    if(one){
        owner.one(event,handler);
    }
    else{
        owner.bind(event,handler);
    }
    for(index=0;index<handlers.length;index+=1){
        owner.bind(event,ownerhandlers[index]);
    }   
}

मुझे लगता है कि "मालिकों" को सिर्फ "हैंडलर" होना चाहिए
जोरील

1

मेरे पास एक ही मुद्दा है और इस विषय को मिला है। उपरोक्त उत्तर उन समस्याओं को हल कर सकते हैं, लेकिन मुझे नहीं लगता कि वे अच्छी योजनाएं हैं।

हमें वास्तविक दुनिया के बारे में सोचने दें।

यदि हम उन उत्तरों का उपयोग करते हैं, तो हमें अपना कोड बदलना होगा। आपको अपनी कोड शैली बदलनी होगी। कुछ इस तरह:

मूल:

$('form').submit(handle);

हैक:

bindAtTheStart($('form'),'submit',handle);

जैसे-जैसे समय बीत रहा है, अपने प्रोजेक्ट के बारे में सोचें। कोड बदसूरत और पढ़ने के लिए मुश्किल है! anthoer कारण सरल है हमेशा बेहतर होता है। यदि आपके पास 10 bindAtTheStart है, तो यह कोई बग नहीं हो सकता है। यदि आपके पास 100 bindAtTheStart है, तो क्या आप वास्तव में सुनिश्चित हैं कि आप उन्हें सही क्रम में रख सकते हैं?

इसलिए यदि आपको एक ही घटना को कई बार बाँधना है। मुझे लगता है कि सबसे अच्छा तरीका नियंत्रण js-file या js-code लोड ऑर्डर है। jquery इवेंट डेटा को कतार के रूप में संभाल सकता है। ऑर्डर फर्स्ट-इन, फर्स्ट-आउट है। आपको किसी भी कोड को बदलने की आवश्यकता नहीं है। बस लोड आदेश बदलें।


0

यहाँ इस पर मेरा शॉट है, jQuery के विभिन्न संस्करणों को कवर:

// Binds a jQuery event to elements at the start of the event chain for that type.
jQuery.extend({
    _bindEventHandlerAtStart: function ($elements, eventType, handler) {
        var _data;

        $elements.bind(eventType, handler);
        // This bound the event, naturally, at the end of the event chain. We
        // need it at the start.

        if (typeof jQuery._data === 'function') {
            // Since jQuery 1.8.1, it seems, that the events object isn't
            // available through the public API `.data` method.
            // Using `$._data, where it exists, seems to work.
            _data = true;
        }

        $elements.each(function (index, element) {
            var events;

            if (_data) {
                events = jQuery._data(element, 'events')[eventType];
            } else {
                events = jQuery(element).data('events')[eventType];
            }

            events.unshift(events.pop());

            if (_data) {
                jQuery._data(element, 'events')[eventType] = events;
            } else {
                jQuery(element).data('events')[eventType] = events;
            }
        });
    }
});

0

कुछ विशेष मामलों में, जब आप यह नहीं बदल सकते हैं कि क्लिक ईवेंट कैसे बाध्य हैं (ईवेंट बाइंडिंग दूसरों के कोड से बनाई गई है), और आप HTML तत्व को बदल सकते हैं, तो यहां एक संभावित समाधान है ( चेतावनी : यह बाइंड करने का अनुशंसित तरीका नहीं है ईवेंट, अन्य डेवलपर इसके लिए आपकी हत्या कर सकते हैं):

<span onclick="yourEventHandler(event)">Button</span>

बाध्यकारी के इस तरीके के साथ, आपका ईवेंट हैंडर पहले जोड़ा जाएगा, इसलिए इसे पहले निष्पादित किया जाएगा।


यह एक समाधान नहीं है, यह एक समाधान पर एक संकेत है। क्या आप यह सुझाव दे रहे हैं कि यह "ऑनक्लिक" हैंडलर उस तत्व पर जा रहा है जिसके पास पहले से ही एक (jQuery) हैंडलर है, या आपका <span> jQuery हैंडलर के साथ तत्व को लपेट रहा है?
शुभ अंक

-2

JQuery 1.5 वादों को पेश करता है, और यहां सबसे सरल कार्यान्वयन है जिसे मैंने निष्पादन के आदेश को नियंत्रित करने के लिए देखा है। Http://api.jquery.com/jquery.when/ पर पूर्ण प्रलेखन

$.when( $('#myDiv').css('background-color', 'red') )
 .then( alert('hi!') )
 .then( myClickFunction( $('#myID') ) )
 .then( myThingToRunAfterClick() );
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.