2011-01-20 32 views
31

Có cách nào để đính kèm một trình xử lý sự kiện jQuery sao cho trình xử lý được kích hoạt trước mọi trình xử lý sự kiện được đính kèm trước đó không? Tôi đã xem qua this article, nhưng mã không hoạt động vì trình xử lý sự kiện không còn được lưu trữ trong một mảng nữa, đó là những gì mã của anh ta mong đợi. Tôi đã cố gắng để tạo tiện ích jQuery để làm những gì tôi muốn, nhưng điều này không làm việc (sự kiện vẫn bắn theo thứ tự chúng được ràng buộc):Gắn các trình xử lý sự kiện jQuery để chúng được kích hoạt đầu tiên

$.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]); 
       } 
      } 
     }); 
    } 
}); 

tự nhiên cách để sắp xếp lại các sự kiện xử lý? Nếu không có, bạn có biết về kỹ thuật tôi có thể áp dụng không? Tôi đang sử dụng jQuery 1.4.1, mặc dù tôi sẽ nâng cấp nếu tôi phải.

+0

Trước tiên, bạn phải lưu trữ tất cả các lệnh 'self.bind (type, handler)' vào một mảng vì ràng buộc là tạo một thể hiện mới của hàm đó. – rxgx

Trả lời

13

Đây là một plugin đơn giản mà tôi đã làm một lúc trở lại. Cho phép bạn ràng buộc một trình xử lý vào đầu danh sách. Nó rất đơn giản, và tôi sẽ không đảm bảo rằng nó hoạt động với các sự kiện không gian tên hoặc bất cứ điều gì đáng kinh ngạc.

Để chỉ đơn giản ràng buộc một nhóm riêng biệt hoặc không gian của các sự kiện, nó sẽ hoạt động.

Ví dụ:http://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()); 
     } 
    }); 
}; 

Hoặc nếu bạn muốn thao tác các mảng của bộ xử lý dưới hình thức khác, chỉ cần có được xử lý cho các phần tử mà bạn muốn, và vận dụng nó tuy nhiên bạn muốn:

Ví dụ:http://jsfiddle.net/gbcUy/1/

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

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

Thật không may, điều này gặp phải vấn đề tương tự như trong bài viết tôi đã đề cập. 'evt' trong mã của bạn không còn là mảng nữa mà là mảng kết hợp. Do đó, 'splice' không hoạt động. Tôi đang sử dụng jQuery 1.4.1 (hoặc cao hơn nếu tôi cần). – Jacob

+0

@ Jacob: Tôi chỉ được thử nghiệm với phiên bản 1.4.2 và mới hơn, và nó thực sự hoạt động. Nó là một mảng rất nhiều. Bạn đã thử các ví dụ tôi đã đăng chưa? – user113716

+0

Tôi sẽ thử với jQuery 1.4.4 và xem nó có hoạt động hay không. – Jacob

1

@patrick: Tôi đã cố gắng giải quyết cùng một vấn đề và giải pháp này thực hiện chính xác những gì tôi cần. Một vấn đề nhỏ là plugin của bạn không xử lý việc đặt tên cho sự kiện mới. tinh chỉnh nhỏ này nên chăm sóc nó:

Thay đổi:

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

tới:

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

gì về điều này? ràng buộc sự kiện và hơn làm điều này:

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

Có một plugin khá tốt đẹp gọi là jQuery.bind-first cung cấp tương tự của tự nhiên on, bind, delegatelive phương pháp mà đẩy một sự kiện để phía trên cùng của đăng ký xếp hàng. Nó cũng tính đến sự khác biệt trong đăng ký sự kiện giữa 1,7 và các phiên bản trước đó. Dưới đây là làm thế nào để sử dụng nó:

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

Như với hầu hết các câu trả lời, những bất lợi lớn là nó dựa trên logic đăng ký sự kiện nội bộ của jQuery và có thể dễ dàng phá vỡ nếu nó thay đổi giống như nó đã làm trong phiên bản 1.7! Nó có thể là tốt hơn cho tuổi thọ của dự án của bạn để tìm một giải pháp mà không liên quan đến cướp nội bộ jQuery.

Trong trường hợp cụ thể của tôi, tôi đã cố gắng nhận hai plugin để phát đẹp. Tôi đã xử lý nó bằng các sự kiện tùy chỉnh như được mô tả trong tài liệu cho the trigger method.Bạn có thể thích ứng với cách tiếp cận tương tự với hoàn cảnh của riêng bạn. Dưới đây là một ví dụ để giúp bạn bắt đầu:

$('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. 
    }); 

Và, trong trường hợp bạn cần phải, dưới đây là cách để thiết lập các thuộc tính trên đối tượng sự kiện truyền cho hàm xử lý và truy cập vào kết quả của các sự kiện cuối cùng before-click để thực hiện:

// 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

đây là một sự kết hợp của một số phương pháp trước bao gồm hỗ trợ cho bộ xử lý, không gian tên, cam kết ràng buộc phi jquery, và một lần hỗ trợ:

$.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

trong Ngoài các câu trả lời được lựa chọn, hãy xem xét nó thiếu các thông số:

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

Như đã trả lời ở đây https://stackoverflow.com/a/35472362/1815779, bạn có thể làm như thế này:

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

Warning: đây là không cách khuyến khích để ràng buộc các sự kiện, các nhà phát triển khác có thể giết bạn vì điều này.

Các vấn đề liên quan