我想实现一个可以“广播”的自定义事件,而不是发送到特定目标。只有那些已将自己注册为此类事件的侦听器的元素才会收到它们。
我的想法如下:
首先,在代码的不同位置,会有表格
的陈述some_subscriber.on_signal( 'some_signal', some_handler );
我使用术语signal
作为“广播事件”的简写。在上面的表达式中,some_subscriber
通过为它提供处理程序,将自身注册为此类信号的一种类型(称为“some_signal”)的监听器。
在代码的其他地方,会有表格
的陈述publisher.signal_types[ 'some_signal' ].broadcast( event_data );
当执行这些语句时,会生成一个新事件并“ broadcast ”。我的意思是,调用broadcast
方法的代码没有关于它发出的信号的侦听器的直接信息。
我在this jsFiddle中实现了这个想法的草图,主要是为了说明我在 1 上面的文字中描述的内容。 (它肯定不是生产级的,我不是特别相信它可以这么做。)
此实施的关键要素如下。首先,发布者对象不会跟踪他们的订阅者,这可以在这样的发布者的工厂方法的实现中看到,如下所示:
function make_publisher ( signal_types ) {
// ...
var _
, signal = {}
, ping = function ( type ) {
signal[ type ].broadcast( ... );
}
;
signal_types.forEach( function ( type ) {
signal[ type ] = $.register_signal_type( type );
} );
return { signal_types: signal_types, ping: ping };
}
此发布者对象仅公开两个项目:它广播的信号类型(signal_types
)和ping
方法。当调用其ping
方法时,发布者通过广播响应信号:
signal[ type ].broadcast( ... )
此广播的最终收件人无法在此代码中看到。
其次,在代码的其他地方,订户将自己注册为这些广播信号的监听器,如此
$( some_selector ).on_signal( signal_type, some_handler );
注意:基本上不可能使用既小又实际的例子来说明此方案的基本原理。这样做的原因是该方案的优势在于它支持发布者代码和订阅者代码之间非常松散的耦合,这是一个在小例子中从不必要的功能。相反,在一个小例子中,实现这种松散耦合的代码总是不必要地复杂化。因此,重要的是要记住,这种明显的过度复杂性是上下文的人为因素。松散耦合在大型项目中非常有用。特别是,通过发布者/订阅者类型模式的松耦合是MVC的基本特征之一。
我的问题是:是否有更好(或至少更标准)的方式来实现“广播”自定义事件的效果?
(我对基于jQuery的答案以及“纯JS”答案感兴趣。)
1 这篇帖子的早期命运多变的版本几乎普遍不理解,并且(当然)是非常典型的向下投票。除了一个例外,我所提出的所有评论都对帖子的前提提出了挑战,并且直接质疑我对事件驱动编程基础知识的掌握等等。我希望通过提出一个至少我的意思的工作示例它不会像我单独用文字描述的那样完全不可思议。幸运的是,我之前发布的一条有用的评论告诉我函数jQuery.Callbacks
。这确实是一个有用的提示;帖子中提到的草图实现基于jQuery.Callbacks
。
功能
答案 0 :(得分:13)
好的。
所以我认为您可以使用原生的 dispatchEvent
和 addEventListener
方法并使用 document
是发布和订阅这些事件的唯一元素。类似的东西:
var myCustomEvent = new Event('someEvent');
document.dispatchEvent(myCustomEvent);
...
document.addEventListener('someEvent', doSomething, false);
要制作跨浏览器,您可以:
var myCustomEvent = new Event('someEvent');
document.dispatchEvent(myCustomEvent);
...
if (document.addEventListener) {
document.addEventListener('someEvent', doSomething, false);
} else {
document.attachEvent('someEvent', doSomething);
}
答案 1 :(得分:2)
我的问题是:是否有更好的(或至少更标准的)方式 实现"广播"自定义活动?
不,在Javascript中没有更标准的发布/订阅方式。它没有直接内置于语言或浏览器中,也没有我所知道的平台标准。
您可以将自己的系统放在一起,有几个选项(大部分您都知道)。
您可以选择特定对象,例如document
对象或window
对象或您创建的新对象,并使用jQuery' s .on()
和.trigger()
将该对象作为中央清算所,以拼凑出类似发布/订阅的模型。如果你愿意,你甚至可以通过将它编码成几个实用函数来隐藏实际使用中该对象的存在。
或者,正如您似乎已经知道的那样,您可以使用jQuery.Callbacks
功能。甚至在jQuery doc中发布/订阅示例代码。
或者,您可以找到提供某种传统发布/订阅模型的第三方库。
或者,您可以从头开始构建自己的,这实际上只涉及保留与特定事件关联的回调函数列表,因此当触发该事件时,您可以调用每个回调函数。
答案 2 :(得分:0)
如果您来到这里寻找jQuery
这样做的方式,请转到:
添加事件广播/发送代码:
语法:
$(<element-name>).trigger(<event-name>);
。
示例:
$.ajax({
...
complete: function () {
// signal to registered listeners that event has occured
$(document).trigger("build_complete");
...
}
});
注册活动的听众:
语法:
$(<element-name>).on(<event-name>, function() {...});
示例:
$(document).on("build_complete", function () {
NextTask.Init();
});
注意:
这样做:$(document).build_complete(function() {...});
会导致错误:Uncaught TypeError: $(...).build_complete is not a function
。
答案 3 :(得分:0)
我知道这个问题早在2015年就已被标记为“答案”,但是一种优雅而简单的解决方案可以使用Redux