【问题标题】:JavaScript trigger multiple events but handle onceJavaScript 触发多个事件但处理一次
【发布时间】:2017-01-16 23:36:55
【问题描述】:

我不知道我是不是第一个遇到这个问题并且不想继续前进的人,但在我看来,其他人应该也经历过。另外,不要介意代码,因为我正在为这个示例编写代码。实际应用思路类似。

假设您有以下控制某个模型的对象:

var model = $({
    name: 'user',
    age: 30,
    sex: 'male'
});

model.on( 'namechange agechange sexchange', function ( event ) {
    console.log( 'Model experienced a ' + event.type );
});

model.triggerHandler( 'namechange' );

上述代码的输出将是Model experienced a namechange

如果我想触发多个事件,代码如下:

model.triggerHandler( 'namechange' );
model.triggerHandler( 'agechange' );
model.triggerHandler( 'sexchange' );

并且输出会相应地重复。

但我真正想要的是当触发方法触发处理程序所绑定的一个或多个事件时触发处理程序一次。

model.triggerHandler( 'namechange agechange' ); // hander is bound to both but called once
model.triggerHandler( 'agechange' ); // hander is bound to one and called once
model.triggerHandler( 'namechange carchange agechange' ); // hander is bound to two of the three but called once

我确实理解由于订阅的工作方式而导致的技术限制。实现必须弄清楚谁订阅了所有这些事件,加入结果并发布事件。更重要的是,event.type 并非旨在表示单个事件名称。

然而,我确信存在满足此类要求的用例。就我而言,它是一个动态指标小部件仪表板。有一个代表各种指标的指标结构。不同的指标在不同的时间间隔更新。不同的小部件依赖于多个指标。从服务器获取指标时,我想为每个指标更改触发一个事件。小部件将刷新其数据。但是,我不希望依赖多个指标多次刷新的小部件。相反,我希望在通知该小部件的哪些指标发生更改后触发处理程序(这会过滤掉与进入处理程序的小部件无关的指标)。

我意识到我可以创建一个metrics.update 事件并传递一组已更改的指标。在处理程序中,我可以确定这是否甚至与小部件有关。但理想情况下,我想避免这一步。

一个想法是定义一个 jquery 插件来缓冲将使用预定义的“魔术”协议的事件:

model.bulkTriggerHandler( 'namechange agechange' );

插件bulkTriggerHandler 可以解析事件字符串并考虑事件范围,然后它可以遍历内部对象并找出它们使用(非常hackish)$._data( object, "events" ) 方法订阅的事件,为每个对象聚合它们各自相关事件列表,并触发某个事件处理程序。这个批量事件处理程序必须通过 model.on( 'bulkUpdate' )... 分配,但这一切都非常 hacky。

无论如何,我会很感激任何 cmets,即使是那些说我应该坚持使用 metrics.update 并且不理会上述内容的人 ;)

【问题讨论】:

  • 你考虑过 jquery bind() 吗?
  • 不,除非最近对 .bind 进行了修订,否则它的工作方式类似于 .on 方法。这里的问题不是绑定到事件,而是触发和处理它们。您不能使用 .trigger( 'eventA eventB' ) 而是立即处理它们。我刚刚发现一张票被提出并解决为 jquery 的“wontfix”:bugs.jquery.com/ticket/12734.

标签: javascript jquery events event-handling eventtrigger


【解决方案1】:

您不应该环绕触发,而应该环绕事件绑定。提供您自己的函数来绑定多个事件。它将为各个事件绑定自己的处理程序。该函数将跟踪发生了哪些事件,当列表中的所有事件发生时,它将调用提供的处理函数。调用者将其称为:

model.multiBind('namechange agechange', function() {
    ...
});

【讨论】:

  • 不需要触发所有绑定事件。当我执行 model.triggerHandler('namechange'); 时,应该调用上述处理程序;和 model.triggerHandler('agechange');和 model.triggerHandler('namechange agechange');来电。也许 multiBind 应该绑定到上述事件和一个特殊的“刷新”事件,它的处理程序应该创建一个触发事件队列。要触发,.multiTrigger 应该触发它指定的每个事件,并通过触发 'flush' 事件来完成它。 Flush 会让 multiBind 知道“事务”已经完成,它可以分发事件。
  • 我想我误解了你想要什么。您写了我真正想要的是在发生多个更改时触发一个处理程序。所以我认为您想等到所有不同的更改事件都发生后再运行处理程序。
【解决方案2】:

我知道这篇文章有点陈旧,但也许我仍然可以提供帮助......

//Define a single function that takes an event object
function handleChange(event)
{
    // Log a string parameterized with event.type
    console.log( 'Model experienced a ' + event.type );
}

// Register handlers one at a time but reuse the function
model.on( 'namechange', handleChange);
model.on( 'agechange', handleChange);
model.on( 'sexchange', handleChange);

能够一次为 N 个事件定义处理程序有点酷,但这似乎是一种避免重复代码的方法。

您总是可以编写一个实用函数,它接受一个数组或任意数量的位置参数,并为您执行重复的.on。我会被这样称呼:

handle(model, ["namechange", "agechange", "sexchange"], handleChange);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-09
    • 1970-01-01
    • 2023-02-02
    相关资源
    最近更新 更多