2011-01-20 15 views
31

Bir jQuery olay işleyicisini, önceden eklenmiş olay işleyicilerinden önce işleyicinin tetikleneceği şekilde eklemenin bir yolu var mı? this article ile karşılaştım, ancak kod çalışmadı çünkü olay işleyicileri bir dizide saklanmadı, bu da kodunun beklendiği gibi. Ne istediğimi yapmak için bir jQuery uzantısı oluşturmak için çalıştı, ama bu (olaylar hala ciltlenmiş sırayla ateş) çalışmıyor:jQuery olay işleyicileri, ilk olarak tetiklenecek şekilde ekleme

$.fn.extend({ 
    bindFirst: function(type, handler) { 

     var baseType = type; 
     var dotIdx = type.indexOf('.'); 
     if (dotIdx >= 0) { 
      baseType = type.substr(0, dotIdx); 
     } 

     this.each(function() { 
      var oldEvts = {}; 
      var data = $.data(this); 
      var events = data.events || data.__events__; 
      var handlers = events[baseType]; 
      for (var h in handlers) { 
       if (handlers.hasOwnProperty(h)) { 
        oldEvts[h] = handlers[h]; 
        delete handlers[h]; 
        // Also tried an unbind here, to no avail 
       } 
      } 

      var self = $(this); 
      self.bind(type, handler); 

      for (var h in oldEvts) { 
       if (oldEvts.hasOwnProperty(h)) { 
        self.bind(baseType, oldEvts[h]); 
       } 
      } 
     }); 
    } 
}); 

olay ele yeniden sıralamak için bir doğal yolu var mı? Eğer yoksa, başvurabileceğim tekniğini biliyor musun? Ben jQuery 1.4.1 kullanıyorum, ama eğer yükseltmeliyim eğer yükseltmeliyim.

+0

Önce, tüm self.bind (tür, işleyici) çağrılarını bir diziye depolamanız gerekir; çünkü bağlama, bu işlevin yeni bir örneğini oluşturuyordur. – rxgx

cevap

13

Bir süre önce yaptığım basit bir eklenti. Bir işleyiciyi listenin başına bağlamanıza izin verir. Bu çok basit ve isimsiz olaylar ya da korkunç bir şey fantezi ile çalışacağını garanti etmem.

Tek veya ayrı bir olay grubunu basitçe bağlamak için çalışmalıdır.

Örnek: sadece istediğiniz öğenin işleyicileri olsun, diğer bazı biçimde işleyicileri Diziyi işlemek ve maniple istiyorsahttp://jsfiddle.net/gbcUy/

$.fn.bindUp = function(type, fn) { 

    type = type.split(/\s+/); 

    this.each(function() { 
     var len = type.length; 
     while(len--) { 
      $(this).bind(type[len], fn); 

      var evt = $.data(this, 'events')[type[len]]; 
      evt.splice(0, 0, evt.pop()); 
     } 
    }); 
}; 

Ya ancak istediğiniz:

Örnek:http://jsfiddle.net/gbcUy/1/

var clickHandlers = $('img').data('events').click; 

clickHandlers.reverse(); // reverse the order of the Array 
+0

Maalesef, bu, bahsettiğim makaledeki aynı sorundan muzdarip. Kodunuzda 'evt' artık bir dizi değil, ilişkilendirici bir dizi. Bu nedenle, 'ekleme' çalışmıyor. JQuery 1.4.1 kullanıyorum (veya gerekirse daha yüksek). – Jacob

+0

@Jacob: Sadece 1.4.2 ve üstü ile test ettim ve gerçekten çalışıyor. Bu bir Array. Gönderdiğim örnekleri denedin mi? – user113716

+0

jQuery 1.4.4 ile çalışacağım ve çalışıp çalışmadığını kontrol edeceğim. – Jacob

1

@patrick: Aynı sorunu çözmeye çalışıyorum ve bu çözüm tam ihtiyacım olan şeyi yapıyor. Küçük bir sorun, eklentinizin yeni etkinlik için ad boşluğu tutmamasıdır. Bu küçük çimdik icabına olmalıdır:

Değiştir:

var evt = $.data(this, 'events')[type[len]]; 

için: Bu konuda

var evt = $.data(this, 'events')[type[len].replace(/\..+$/, '')]; 
1

ne olacak? olay bağlamak ve benden daha: Kayıt üstüne bir olay itmek yerli on, bind, delegate ve live yöntemlerin benzerlerini sağlamaktadır jQuery.bind-first adında oldukça güzel bir eklenti vardır

handlers.unshift(handlers.pop()); 
6

sıraya. Ayrıca, 1.7 ve önceki sürümler arasındaki olay kaydındaki farkları da dikkate alır. İşte kullanmak için:

$('button') 
    .on  ('click', function() { /* Runs second */ }) 
    .onFirst('click', function() { /* Runs first */ }); 

bu cevapların çoğu olduğu gibi, büyük dezavantajı jQuery'nin iç etkinlik kaydı mantığına dayanır ve kolaylıkla değiştirir benzeri eğer sürüm 1.7 yaptığı kırılabilir olmasıdır! Projenizin jQuery internals'ı içermeyen bir çözüm bulması, projenizin uzun ömürlü olması için daha iyi olabilir. Özel durumumda, güzel oynamak için iki eklenti almaya çalışıyordum. Ben the trigger method belgelerinde açıklandığı gibi özel olayları kullanarak ele.Kendi durumunuza benzer bir yaklaşıma uyum sağlayabilirsiniz.

$('button') 
    .on('click', function() { 
     // Declare and trigger a "before-click" event. 
     $(this).trigger('before-click'); 

     // Subsequent code run after the "before-click" events. 
    }) 
    .on('before-click', function() { 
     // Run before the main body of the click event. 
    }); 

Ve, eğer gerek, burada işleyici işlevine aktarılan olay nesnesinin özelliklerini ayarlamak ve yürütmek son before-click olayın sonucunu erişmek için:: Burada başlangıç ​​için bir örnek

İşte
// Add the click event's pageX and pageY to the before-click event properties. 
var beforeClickEvent = $.Event('before-click', { pageX: e.pageX, pageY: e.pageY }); 
$(this).trigger(beforeClickEvent); 

// beforeClickEvent.result holds the return value of the last before-click event. 
if (beforeClickEvent.result === 'no-click') return; 
0

işleyicileri, ad alanı olmayan jquery bağlamaları için destek dahil bazı önceki yöntemlerin bir kombinasyonu ve destek kez: In

$.fn.oneFirst = function(event_type, event_callback, handler) { 
    return this.bindFirst(event_type, event_callback, handler, "one"); 
}, 
$.fn.bindFirst = function(event_type, event_callback, handler, bind_type) { 
    var event_types = event_type.split(/\s+/); 
    var pos; 
    handler = (handler == undefined ? event_callback : handler); 
    event_callback = (typeof event_callback == "function" ? {} : event_callback); 

    this.each(function() { 
     var $this = $(this); 
     for (var i in event_types) { // each bound type 
      event_type = event_types[i]; 

      var event_namespace = ((pos = event_type.indexOf(".")) > 0 ? event_type.substring(pos) : ""); 
      event_type = (pos > 0 ? event_type.substring(0, pos) : event_type); 
      var current_attr_listener = this["on" + event_type]; 

      if (current_attr_listener) { // support non-jquery binded events 
       $this.bind(event_type, function(e) { 
        return current_attr_listener(e.originalEvent); 
       }); 
       this["on" + event_type] = null; 
      } 

      if (bind_type == "one") { 
       $this.one(event_type + event_namespace, event_callback, handler); 
      } 
      else { 
       $this.bind(event_type + event_namespace, event_callback, handler); 
      } 

      var all_events = $.data(this, 'events') || $._data(this).events; 
      var type_events = all_events[event_type]; 
      var new_event = type_events.pop(); 
      type_events.unshift(new_event); 
     } 
    }); 
}; 
1

Seçilen cevaba eklenmesi, bu parametreler eksik düşünün:

jQuery.fn.bindUp = function (type, parameters, fn) { 
    type = type.split(/\s+/); 

    this.each(function() { 
     var len = type.length; 
     while (len--) { 
      if (typeof parameters === "function") 
       jQuery(this).bind(type[len], parameters); 
      else 
       jQuery(this).bind(type[len], parameters, fn); 

      var evt = jQuery._data(this, 'events')[type[len]]; 
      evt.splice(0, 0, evt.pop()); 
     } 
    }); 
}; 
1

olarak burada https://stackoverflow.com/a/35472362/1815779 cevap, böyle yapabilirsiniz:

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

Uyarı: Bu bağlamak için önerilen yol değil olduğunu Olaylar, diğer geliştiriciler bunun için seni öldürebilir.

İlgili konular