jQuery中的自定义事件?


180

我正在寻找有关如何以最佳方式在jquery中实现自定义事件处理的输入。我知道如何从dom元素(如“ click”等)中捕获事件,但是我正在构建一个小的javascript库/插件来处理一些预览功能。

我有一个脚本正在运行,以从一组规则和数据/用户输入中更新dom元素中的某些文本,但是现在我需要该脚本可能无法知道的其他元素中显示的相同文本。我需要的是一个很好的模式,以某种方式观察此脚本产生所需的文本。

那么我该怎么做呢?我是否忽略了jquery中的某些内置功能来引发/处理用户事件,还是需要一些jquery插件来做到这一点?您认为处理此问题的最佳方法/插件是什么?


3
如果有人在看这个问题,还有另一个框架,knockoutjs.com实际上可以解决我的老问题。
PerHornshøj-Schierbeck,2011年

2
看到我不断从这个问题中获得声誉,人们一定仍在阅读它。我只想更新我当前选择的客户端mvc框架:angularjs.org
PerHornshøj-Schierbeck2014年

尽管它与angular v1完全不同,但是Angular2(angular.io)表现出了很大的希望,一旦它超出beta / rc,它将成为我的首选。
PerHornshøj-Schierbeck'16

Answers:


105

看看这个:

(根据http://web.archive.org/web上的存档版本,从过期的博客页面http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/中转载。 /20130120010146/http://jamiethompson.co.uk/web/2008/06/17/publish-subscribe-with-jquery/


使用jQuery发布/订阅

2008年6月17日

为了编写集成有Google Gears脱机功能的jQuery UI,我一直在尝试一些代码以使用jQuery轮询网络连接状态。

网络检测对象

基本前提很简单。我们创建了一个网络检测对象的实例,该实例将定期轮询URL。如果这些HTTP请求失败,我们可以假定网络连接已丢失,或者当前服务器根本无法访问。

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

您可以在此处查看演示。将您的浏览器设置为脱机工作,然后看看会发生什么……。不,不是很令人兴奋。

触发并绑定

令人兴奋的是(或者至少让我激动的是)状态通过应用程序中继的方法。我偶然发现了一种使用jQuery的trigger和bind方法实现发布/订阅系统的未曾讨论过的方法。

演示代码比实际需要的更加笨拙。网络检测对象将“状态”事件发布到主动侦听它们的文档,然后将“通知”事件发布给所有订户(稍后会详细介绍)。其背后的原因是,在现实世界的应用程序中,可能会有更多逻辑来控制何时以及如何发布“通知”事件。

$(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
    */
});

由于jQuery的DOM中心方法,事件被发布到DOM元素上(触发)。这可以是常规事件的窗口或文档对象,也可以使用选择器生成jQuery对象。我在演示中采用的方法是创建一种几乎命名空间的方法来定义订户。

要成为订户的DOM元素仅用“订户”和“ networkDetection”进行分类。然后,通过触发以下事件的通知事件,我们可以将事件仅发布到这些元素(演示中只有一个)$(“.subscriber.networkDetection”)

然后#notifier,属于.subscriber.networkDetection订户组的div 绑定了一个匿名函数,有效地充当了侦听器。

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

所以,你去了。一切都很冗长,我的例子一点也不令人兴奋。它也没有展示您可以使用这些方法做的任何有趣的事情,但是,如果有任何人有兴趣挖掘源代码,可以自由使用。所有代码均内嵌在演示页面的开头


正是我在寻找什么。他可能是对的,但我不禁想到jquery需要直接支持或插件来更优雅地处理它。我会稍等一下,看看是否还有其他问题可以解决,然后再提出答案:)
PerHornshøj-Schierbeck'08

6
这是某处的报价吗?如果是这样,请引用您的来源,并提供一个链接(如果仍然存在)。
Aryeh Leib Taurog

1
是的,它是引用,在编辑历史记录中是此链接,当前无法访问。存档页面在这里
斯塔诺

1
本·阿尔曼Ben Alman)编写了一个小巧的jQuery pub sub插件。非常优雅。
巴尼(Barney)2013年

127

接受的答案中提供的链接显示了一种使用jQuery 实现pub / sub系统的好方法,但是我发现该代码有些难以阅读,因此这是我的简化代码版本:

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
我真的很喜欢这个答案。任何人都可以阅读关于trigger()bind()(和on())的文档,但是此答案提供了使用jquery创建事件总线(发布/子系统)的具体示例。
–losdordorje

1
太棒了 我需要知道的一切。
Patrick Fisher

我发现,如果在触发自定义事件时传递一个数组(长度> 1),那么侦听器将在其参数中获取所有数组项,因此最终将得到n许多参数。
vsync 2014年

侦听器中处理多个参数的解决方案:var eventData = [].slice.call(arguments).splice(1)
vsync

2
有没有#notifier虚拟元素的方法吗?如果我有一个JavaScript库,并且想要一个对象公开事件,则不能确定页面上存在哪些元素。
AaronLS 2014年

21

我认为是..可以“绑定”自定义事件,例如(来自: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
我正在寻找引发事件并让订阅者/听众触发的方法。不手动触发它,因为举起的物体不知道谁在听...
PerHornshøj-Schierbeck

2
这段代码是这样做的,不是吗?myCustomEvent引发后,顶部的绑定将添加一个侦听器。
Sprintstar 2013年

15

我有一个类似的问题,但实际上是在寻找不同的答案。我正在寻找一个自定义事件。例如,而不是总是这样说:

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

我想将其缩写为:

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

触发和绑定并不能说明全部-这是一个JQuery插件。 http://docs.jquery.com/插件/作者

“ enterKey”函数作为属性附加到jQuery.fn-这是所需的代码:

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

上面的优点是您可以在链接侦听器上优雅地处理键盘输入,例如:

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

编辑:更新以正确地将正确的this上下文传递给处理程序,并将所有返回值从处理程序返回给jQuery(例如,如果您要取消事件并冒泡的话)。更新以将适当的jQuery事件对象传递给处理程序,包括键代码和取消事件的功能。

旧的jsfiddle:http : //jsfiddle.net/b9chris/VwEb9/24/


克里斯-该功能运行完美。唯一不起作用的是访问此变量。我能够使用e.currentTarget来访问它。但我想知道是否有更有效的方法。
Addy 2012年

很好地抓住了这个错误。是的,如果您从handler(ev)更改第5行;到:handler.call(this,ev); 那么此参数将与标准jquery事件处理程序中的通常情况相同。jsfiddle.net/b9chris/VwEb9
Chris Moschini

您还知道另一种实现此方法的方法吗?我正在尝试使用此示例,但该示例scroll不会传播。我认为,与其让侦听器硬编码到正文,我还需要on绑定了-event 的元素来自行触发该事件。
·范·德·沃尔

我不确定您要问的情况;最好与代码示例一起问一个问题?
克里斯·莫斯基尼

9

这是一篇旧文章,但我将尝试使用新信息进行更新。

要使用自定义事件,您需要将其绑定到某个DOM元素并触发它。所以你需要使用

.on()方法将事件类型和事件处理函数作为参数。可选地,它也可以接收与事件相关的数据作为其第二个参数,从而将事件处理功能推到第三个参数。传递的任何数据将可用于事件对象的data属性中的事件处理功能。事件处理函数始终将事件对象作为其第一个参数。

.trigger()方法将事件类型作为其参数。(可选)它也可以采用值数组。这些值将作为事件对象之后的参数传递给事件处理函数。

代码如下:

$(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"] );

很好的解释可以在这里这里找到。为什么这确实有用?我在Twitter工程师的出色解释中找到了如何使用它。

PS在普通的javascript中,您可以使用新的CustomEvent进行此操作,但要注意IE和Safari问题。


3

这是我编写自定义事件的方式:

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

当然,您可以做

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

但是我写的方式允许您通过执行以下操作来检测用户是否阻止了默认操作

var prevented = event.isDefaultPrevented();

这使您可以侦听最终用户停止处理特定事件的请求,例如,如果您单击表单中的按钮元素,但是如果出现错误,则不想在表单中发布。


然后我通常会听这样的事件

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

再一次,你可以做

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

但是我总是发现这有些不安全,尤其是在团队中工作时。

以下内容没有任何问题:

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

但是,假设出于任何原因我都需要取消绑定此事件(想象一个禁用的按钮)。那我就要做

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

这将从中删除所有eventname事件$(element)。您不知道将来是否有人还会将事件绑定到该元素,并且您也会无意中取消该事件的绑定

避免这种情况的安全方法是通过以下方式为事件命名空间

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

最后,您可能已经注意到第一行是

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

个人总是在绑定事件之前取消绑定该事件,只是为了确保同一事件处理程序不会被多次调用(假设这是付款表单上的“提交”按钮,并且该事件已被绑定5次)


好的方法。+1表示名称空间。
奥罗弗拉塔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.