Các sự kiện tùy chỉnh trong jQuery?


180

Tôi đang tìm kiếm một số thông tin về cách triển khai sự kiện tùy chỉnh trong jquery một cách tốt nhất. Tôi biết cách kết nối các sự kiện từ các thành phần dom như 'click', v.v., nhưng tôi đang xây dựng một thư viện / plugin javascript nhỏ để xử lý một số chức năng xem trước.

Tôi đã có một tập lệnh đang chạy để cập nhật một số văn bản trong phần tử dom từ một bộ quy tắc và dữ liệu / dữ liệu người dùng tôi nhận được, nhưng bây giờ tôi cần cùng một văn bản được hiển thị trong các yếu tố khác mà tập lệnh này không thể biết được. Những gì tôi cần là một mô hình tốt để bằng cách nào đó quan sát kịch bản này tạo ra văn bản cần thiết.

Vậy làm thế nào để tôi làm điều này? Tôi đã bỏ qua một số chức năng dựng sẵn trong jquery để nâng cao / xử lý các sự kiện của người dùng hay tôi cần một số plugin jquery để làm điều đó? Bạn nghĩ gì là cách tốt nhất / plugin để xử lý việc này?


3
Có một khuôn khổ khác, knoutjs.com thực sự có thể giải quyết vấn đề cũ của tôi, nếu bất cứ ai nhìn vào câu hỏi này đều cần nó.
Per Hornshøj-Schierbeck

2
Thấy tôi tiếp tục nhận được danh tiếng từ câu hỏi này, mọi người vẫn phải đọc nó. Tôi chỉ muốn cập nhật sự lựa chọn hiện tại của tôi về khung mvc phía khách hàng: angularjs.org
Per Hornshøj-Schierbeck

Mặc dù nó hoàn toàn khác với v1 góc, Angular2 ( angular.io ) cho thấy rất nhiều hứa hẹn và sẽ là lựa chọn đầu tiên của tôi khi nó hết beta / RC.
Per Hornshøj-Schierbeck

Câu trả lời:


105

Hãy xem này:

(in lại từ trang blog đã hết hạn http://jamiethndry.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ dựa trên phiên bản lưu trữ tại http://web.archive.org/web /20130120010146/http://jamiethndry.co.uk/web/2008/06/17/publish-subscribe-with-jquery/ )


Xuất bản / Đăng ký với jQuery

Ngày 17 tháng 6 năm 2008

Với mục đích viết Giao diện người dùng jQuery được tích hợp với chức năng ngoại tuyến của Google Gears, tôi đã chơi với một số mã để thăm dò tình trạng kết nối mạng bằng jQuery.

Đối tượng phát hiện mạng

Tiền đề cơ bản là rất đơn giản. Chúng tôi tạo một phiên bản của một đối tượng phát hiện mạng sẽ thăm dò URL theo định kỳ. Nếu các yêu cầu HTTP này không thành công, chúng tôi có thể cho rằng kết nối mạng đã bị mất hoặc máy chủ đơn giản là không thể truy cập được tại thời điểm hiện tại.

$.networkDetection = function(url,interval){
    var url = url;
    var interval = interval;
    online = false;
    this.StartPolling = function(){
        this.StopPolling();
        this.timer = setInterval(poll, interval);
    };
    this.StopPolling = function(){
        clearInterval(this.timer);
    };
    this.setPollInterval= function(i) {
        interval = i;
    };
    this.getOnlineStatus = function(){
        return online;
    };
    function poll() {
        $.ajax({
            type: "POST",
            url: url,
            dataType: "text",
            error: function(){
                online = false;
                $(document).trigger('status.networkDetection',[false]);
            },
            success: function(){
                online = true;
                $(document).trigger('status.networkDetection',[true]);
            }
        });
    };
};

Bạn có thể xem bản demo ở đây. Đặt trình duyệt của bạn hoạt động ngoại tuyến và xem điều gì xảy ra. không, nó không thú vị lắm

Kích hoạt và ràng buộc

Điều thú vị mặc dù (hoặc ít nhất là điều khiến tôi hứng thú) là phương thức mà trạng thái được chuyển tiếp qua ứng dụng. Tôi đã vấp phải một phương pháp chủ yếu chưa được thảo luận về việc triển khai hệ thống pub / sub bằng cách sử dụng các phương thức liên kết và kích hoạt của jQuery.

Mã trình diễn khó hiểu hơn mức cần thiết. Đối tượng phát hiện mạng xuất bản các sự kiện 'trạng thái' lên tài liệu chủ động lắng nghe chúng và lần lượt xuất bản các sự kiện 'thông báo' cho tất cả những người đăng ký (nhiều hơn về những sự kiện sau). Lý do đằng sau điều này là trong một ứng dụng trong thế giới thực, có thể sẽ có một số điều khiển logic hơn khi nào và làm thế nào các sự kiện 'thông báo' được công bố.

$(document).bind("status.networkDetection", function(e, status){
    // subscribers can be namespaced with multiple classes
    subscribers = $('.subscriber.networkDetection');
    // publish notify.networkDetection even to subscribers
    subscribers.trigger("notify.networkDetection", [status])
    /*
    other logic based on network connectivity could go here
    use google gears offline storage etc
    maybe trigger some other events
    */
});

Do các sự kiện tiếp cận trung tâm DOM của jQuery được xuất bản thành (được kích hoạt) các phần tử DOM. Đây có thể là cửa sổ hoặc đối tượng tài liệu cho các sự kiện chung hoặc bạn có thể tạo đối tượng jQuery bằng bộ chọn. Cách tiếp cận tôi đã thực hiện với bản demo là tạo ra một cách tiếp cận gần như được đặt tên để xác định người đăng ký.

Các phần tử DOM sẽ là người đăng ký được phân loại đơn giản với thuê bao của người dùng trực tuyến và mạng mạngDetection trực tiếp. Sau đó, chúng tôi chỉ có thể xuất bản các sự kiện cho các yếu tố này (trong đó chỉ có một sự kiện trong bản demo) bằng cách kích hoạt một sự kiện thông báo trên$(“.subscriber.networkDetection”)

Các #notifierdiv đó là một phần của .subscriber.networkDetectionnhóm các thuê bao sau đó có một chức năng ẩn danh liên kết với nó, hoạt động có hiệu quả như một người biết lắng nghe.

$('#notifier').bind("notify.networkDetection",function(e, online){
    // the following simply demonstrates
    notifier = $(this);
    if(online){
        if (!notifier.hasClass("online")){
            $(this)
                .addClass("online")
                .removeClass("offline")
                .text("ONLINE");
        }
    }else{
        if (!notifier.hasClass("offline")){
            $(this)
                .addClass("offline")
                .removeClass("online")
                .text("OFFLINE");
        }
    };
});

Vì vậy, có bạn đi. Đó là tất cả dài dòng và ví dụ của tôi không thú vị chút nào. Nó cũng không giới thiệu bất cứ điều gì thú vị mà bạn có thể làm với các phương pháp này, nhưng nếu bất kỳ ai cũng muốn tìm hiểu về nguồn này thì cảm thấy thoải mái. Tất cả các mã là nội tuyến trong phần đầu của trang demo


Tuyệt vời những gì tôi đang tìm kiếm. Anh ấy có lẽ đúng rằng đó là cách để đi, nhưng tôi không thể nghĩ rằng jquery cần hỗ trợ trực tiếp hoặc một plugin để xử lý nó một cách duyên dáng hơn. Tôi sẽ đợi một chút và xem liệu có vấn đề nào khác xảy ra không trước khi tôi đánh dấu câu trả lời :)
Per Hornshøj-Schierbeck

6
Đây có phải là một trích dẫn từ đâu đó? Nếu vậy, vui lòng trích dẫn nguồn của bạn và cung cấp một liên kết, nếu nó vẫn tồn tại.
Aryeh Leib Taurog

1
Có, đó là trích dẫn, trong lịch sử chỉnh sửa là liên kết này , hiện tại nó không thể truy cập được. Trang lưu trữ ở đây .
Stano

1
Ben Alman đã viết một plugin phụ pub pub nhỏ xíu (nhỏ xíu) . Nó cực kỳ thanh lịch.
Barney

127

Liên kết được cung cấp trong câu trả lời được chấp nhận cho thấy một cách hay để triển khai hệ thống pub / sub bằng jQuery, nhưng tôi thấy mã hơi khó đọc, vì vậy đây là phiên bản mã đơn giản của tôi:

http://jsfiddle.net/tFw89/5/

$(document).on('testEvent', function(e, eventInfo) { 
  subscribers = $('.subscribers-testEvent');
  subscribers.trigger('testEventHandler', [eventInfo]);
});

$('#myButton').on('click', function() {
  $(document).trigger('testEvent', [1011]);
});

$('#notifier1').on('testEventHandler', function(e, eventInfo) { 
  alert('(notifier1)The value of eventInfo is: ' + eventInfo);
});

$('#notifier2').on('testEventHandler', function(e, eventInfo) { 
  alert('(notifier2)The value of eventInfo is: ' + eventInfo);
});

10
Tôi thực sự thích câu trả lời này. Bất cứ ai cũng có thể đọc các tài liệu trên trigger () bind () (và on ()), nhưng câu trả lời này cung cấp một ví dụ cụ thể về việc tạo một bus sự kiện (pub / sub system) bằng jquery.
mất

1
Bravo. Tất cả mọi thứ tôi cần biết.
Patrick Fisher

Tôi đã thấy rằng nếu bạn vượt qua một mảng (trong đó độ dài> 1) khi bạn kích hoạt một sự kiện tùy chỉnh, thì người nghe sẽ nhận được tất cả các mục mảng trong các đối số của nó, vì vậy bạn sẽ kết thúc với nsố lượng đối số.
vsync

giải pháp cho việc xử lý nhiều đối số trong trình nghe:var eventData = [].slice.call(arguments).splice(1)
vsync

2
Có cách nào để làm điều này mà không cần các phần tử giả #notifier không? Nếu tôi có thư viện javascript và muốn một đối tượng phơi bày một sự kiện, tôi không thể chắc chắn những yếu tố nào tồn tại trên trang.
AaronLS

21

Tôi nghĩ vậy .. có thể 'liên kết' các sự kiện tùy chỉnh, như (từ: http://docs.jquery.com/Events/bind#typedatafn ):

 $("p").bind("myCustomEvent", function(e, myName, myValue){
      $(this).text(myName + ", hi there!");
      $("span").stop().css("opacity", 1)
               .text("myName = " + myName)
               .fadeIn(30).fadeOut(1000);
    });
    $("button").click(function () {
      $("p").trigger("myCustomEvent", [ "John" ]);
    });

1
Tôi đang tìm cách để nâng cao sự kiện và kích hoạt người đăng ký / người nghe trên đó. Không kích hoạt thủ công vì đối tượng nâng cao không biết ai đang lắng nghe ...
Per Hornshøj-Schierbeck

2
Mã này làm điều này, phải không? myCustomEventđược nâng lên, các liên kết ở đầu thêm một người nghe.
Sprintstar

15

Tôi đã có một câu hỏi tương tự, nhưng thực sự đang tìm kiếm một câu trả lời khác nhau; Tôi đang tìm cách tạo ra một sự kiện tùy chỉnh. Ví dụ thay vì luôn luôn nói điều này:

$('#myInput').keydown(function(ev) {
    if (ev.which == 13) {
        ev.preventDefault();
        // Do some stuff that handles the enter key
    }
});

Tôi muốn viết tắt nó thành này:

$('#myInput').enterKey(function() {
    // Do some stuff that handles the enter key
});

kích hoạt và liên kết không nói lên toàn bộ câu chuyện - đây là một plugin JQuery. http://docs.jquery.com/Plugins/Authoring

Hàm "enterKey" được đính kèm dưới dạng một thuộc tính cho jQuery.fn - đây là mã bắt buộc:

(function($){
    $('body').on('keydown', 'input', function(ev) {
        if (ev.which == 13) {
            var enterEv = $.extend({}, ev, { type: 'enterKey' });
            return $(ev.target).trigger(enterEv);
        }
    });

    $.fn.enterKey = function(selector, data, fn) {
        return this.on('enterKey', selector, data, fn);
    };
})(jQuery);

http://jsfiddle.net/b9chris/CkvuJ/4/

Một điều thú vị ở trên là bạn có thể xử lý đầu vào bàn phím một cách duyên dáng trên các trình nghe liên kết như:

$('a.button').on('click enterKey', function(ev) {
    ev.preventDefault();
    ...
});

Chỉnh sửa: Được cập nhật để chuyển đúng thisngữ cảnh cho trình xử lý và trả lại bất kỳ giá trị trả về nào từ trình xử lý cho jQuery (ví dụ trong trường hợp bạn đang tìm cách hủy sự kiện và tạo bọt). Đã cập nhật để chuyển một đối tượng sự kiện jQuery thích hợp cho các trình xử lý, bao gồm mã khóa và khả năng hủy sự kiện.

Jsfiddle cũ: http://jsfiddle.net/b9chris/VwEb9/24/


Chris - Hàm hoạt động hoàn hảo .. điều duy nhất không hoạt động là truy cập vào biến này .. tôi có thể truy cập nó bằng e.cienTarget .. nhưng tự hỏi liệu có cách nào hiệu quả hơn không.
Addy

Bắt tốt về lỗi đó. Có, nếu bạn thay đổi dòng 5 từ handler (ev); đến: handler.call (này, ev); sau đó đối số này sẽ như bình thường trong các trình xử lý sự kiện jquery tiêu chuẩn. jsfiddle.net/b9chris/VwEb9
Chris Moschini

Bạn có biết một cách để thực hiện điều này theo cách khác không? Tôi đang cố gắng sử dụng ví dụ này nhưng scrollkhông truyền bá. Tôi nghĩ rằng thay vì khiến người nghe bị mã hóa vào cơ thể, tôi cần các yếu tố có onliên quan đến họ để tự phát sáng sự kiện.
Gust van de Wal

Tôi không chắc về kịch bản bạn đang hỏi về; có thể được hỏi tốt nhất như một câu hỏi với mẫu mã?
Chris Moschini

9

Đây là một bài viết cũ, nhưng tôi sẽ cố gắng cập nhật nó với một thông tin mới.

Để sử dụng các sự kiện tùy chỉnh, bạn cần liên kết nó với một số phần tử DOM và để kích hoạt nó. Vì vậy, bạn cần phải sử dụng

Phương thức .on () lấy một loại sự kiện và một hàm xử lý sự kiện làm đối số. Tùy chọn, nó cũng có thể nhận dữ liệu liên quan đến sự kiện làm đối số thứ hai, đẩy chức năng xử lý sự kiện sang đối số thứ ba. Mọi dữ liệu được truyền sẽ có sẵn cho chức năng xử lý sự kiện trong thuộc tính dữ liệu của đối tượng sự kiện. Hàm xử lý sự kiện luôn nhận đối tượng sự kiện là đối số đầu tiên của nó.

Phương thức .trigger () lấy một loại sự kiện làm đối số của nó. Tùy chọn, nó cũng có thể mất một loạt các giá trị. Các giá trị này sẽ được chuyển đến hàm xử lý sự kiện dưới dạng đối số sau đối tượng sự kiện.

Mã trông như thế này:

$(document).on("getMsg", {
    msg: "Hello to everyone",
    time: new Date()
}, function(e, param) {
    console.log( e.data.msg );
    console.log( e.data.time );
    console.log( param );
});

$( document ).trigger("getMsg", [ "Hello guys"] );

Giải thích tốt đẹp có thể được tìm thấy ở đâyở đây . Tại sao chính xác điều này có thể hữu ích? Tôi tìm thấy làm thế nào để sử dụng nó trong lời giải thích tuyệt vời này từ kỹ sư twitter .

PS Trong javascript đơn giản, bạn có thể làm điều này với CustomEvent mới , nhưng hãy cẩn thận với các vấn đề về IE và Safari.


3

Đây là cách tôi tác giả các sự kiện tùy chỉnh:

var event = jQuery.Event('customEventName');
$(element).trigger(event);

Cấp, bạn chỉ có thể làm

$(element).trigger('eventname');

Nhưng cách tôi viết cho phép bạn phát hiện xem người dùng có ngăn chặn mặc định hay không bằng cách thực hiện

var prevented = event.isDefaultPrevented();

Điều này cho phép bạn lắng nghe yêu cầu của người dùng cuối để ngừng xử lý một sự kiện cụ thể, chẳng hạn như nếu bạn nhấp vào một yếu tố nút trong một biểu mẫu nhưng không muốn biểu mẫu để đăng nếu có lỗi.


Sau đó tôi thường nghe các sự kiện như vậy

$(element).off('eventname.namespace').on('eventname.namespace', function () {
    ...
});

Một lần nữa, bạn có thể làm

$(element).on('eventname', function () {
    ...
});

Nhưng tôi luôn thấy điều này không an toàn, đặc biệt nếu bạn làm việc trong một nhóm.

Không có gì sai với những điều sau đây:

$(element).on('eventname', function () {});

Tuy nhiên, giả sử rằng tôi cần hủy liên kết sự kiện này vì bất kỳ lý do gì (hãy tưởng tượng một nút bị vô hiệu hóa). Sau đó tôi sẽ phải làm

$(element).off('eventname', function () {});

Điều này sẽ loại bỏ tất cả các eventnamesự kiện từ $(element). Bạn không thể biết liệu ai đó trong tương lai cũng sẽ liên kết một sự kiện với yếu tố đó hay không và bạn cũng vô tình hủy kết nối sự kiện đó.

Cách an toàn để tránh điều này là không gian tên các sự kiện của bạn bằng cách thực hiện

$(element).on('eventname.namespace', function () {});

Cuối cùng, bạn có thể nhận thấy rằng dòng đầu tiên là

$(element).off('eventname.namespace').on('eventname.namespace', ...)

Cá nhân tôi luôn hủy liên kết một sự kiện trước khi ràng buộc nó chỉ để đảm bảo rằng trình xử lý sự kiện tương tự không bao giờ được gọi nhiều lần (hãy tưởng tượng đây là nút gửi trên một hình thức thanh toán và sự kiện đã bị ràng buộc 5 lần)


cách tiếp cận tốt đẹp. +1 cho không gian tên.
Aurovrata
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.