我目前正在做我的第一个backbone.js应用程序。事件的概念对我来说很熟悉,但我在问我是否应该使用中央事件调度器。通常我看到这两种方法:
- 直接连接事件发布者和事件接收者。(我开始用这种方法)
- 使用事件总线并将发布者和接收者连接到该总线。
在应用程序的长时间可维护性和事件的可追溯性方面,使用事件总线是否有利?
是使用中央事件总线还是直接将事件连接在一起,应根据具体情况进行评估。根据具体情况,有时你会偏爱其中之一。
我将尽可能使用中央事件总线,因为发布者和接收者不是紧密耦合的。在我看来,这使您的代码更易于维护和灵活。
我发现中央事件总线非常有用,当你有:
- 一个事件发布实例和多个事件接收者。
- 多个事件发布实例和单个事件接收者
当事件接收方实例或发布者实例是动态的,因此在应用程序的生命周期中被创建和销毁时,中央事件总线在上述情况下的好处变得更加明显。作为一个例子,考虑以下单页应用程序:
- 单页应用必须拉伸以适应浏览器的窗口宽度。
- 单页应用程序主要是一组选项卡视图,但是选项卡的数量是动态的,因为它们是由用户创建和销毁的
- 选项卡的内容都是不同的,除了它们有一个主要的内容区域,必须在考虑到其他兄弟元素的宽度后拉伸以适应可用的宽度
- 由于选项卡的内容不断变化,需要在许多不同的点调整大小。
在上面的例子中,不管具体的场景如何,中心总线模型都工作得很好。代码示例如下:
应用程序级别
var App = {
init: function () {
// Event to resize width of element to remaining width
App.Events.on("fitRemainingWidth:app", this.fitRemainingWidth);
},
// event pub sub for the app.
Events: _.extend({}, Backbone.Events),
// function that expands an element, or elements to the remaining width in the window.
fitRemainingWidth: function(targetEls) {
var els = $(targetEls);
_.each(els, function (e) {
var el = $(e);
var cont = el.parent();
newWidth = cont.innerWidth();
otherElements = cont.children().not(el);
otherElementsWidth = 0;
otherElements.each(function () {
otherElementsWidth += $(this).outerWidth();
});
el.width(newWidth - otherElementsWidth);
});
}
}
在你的视图
当某个东西需要调整大小时,触发事件,例如:
App.Events.trigger("fitRemainingWidth:app", this.$(".main-content"), this);
正如你所看到的,这真的很有用,因为fitRemainingWidth函数可以应用于任何东西,你永远不知道将来哪个视图可能会使用它,或者什么时候需要调用它。
所以我想我应该移动到当我发现不使用中央事件总线优选。我相信还有其他情况,但对我来说最主要的是当接收者需要连接到发布者的特定实例时。例如,如果我们继续使用选项卡应用程序示例,假设每个选项卡的内容是特定人员邮箱的分屏视图。在每个拆分视图中都有一个显示电子邮件集合的列表窗格和一个显示列表中当前选定消息内容的阅读窗格。
在本例中,我们希望在点击电子邮件时触发"selected:email"事件,并将相应的阅读窗格绑定到它,以便它可以显示电子邮件的内容。
假设我们打开了十个邮箱选项卡,每个选项卡都有自己的电子邮件列表窗格和阅读窗格。这样就有10个邮件列表和10个阅读窗格。如果我要在这个场景中使用中央事件总线,当我从一个列表中触发"selected:email"时,从事件总线接收这些事件的阅读窗格将需要具有自己的智能,以尝试确定所选的电子邮件是否需要显示。每个阅读窗格都试图解决这个问题是不可取的,因为这涉及到不必要的逻辑。对于一个阅读窗格来说,接收一个带有email对象的"selected:email"事件并显示要好得多。
因此,在这种情况下,最好让每个邮箱选项卡视图负责连接其特定子视图实例及其模型和集合的事件。在我们的示例中,这意味着带有其集合的电子邮件列表视图的特定实例和阅读窗格视图的特定关联实例。
总之,我建议每种情况都有用例,您应该尝试明智地为您遇到的每种情况选择正确的方法。两者都使用,并学会找出适合哪种情况的方法。
最后,关于事件的可追溯性,您始终可以在事件总线中为On
和Off
函数编写包装器,该包装器既调用正常的On
和Off
函数,又向包含哪些对象绑定到哪些事件的寄存器添加/删除信息。您可以使用它进行调试,并将有关这些对象的信息写入控制台,这样您就可以清楚地了解事件总线及其侦听器在任何时间点的状态。我从来没有想过这样做,但你没有理由不这样做;)
Post Edit: tsiki关于使用本地事件总线的评论是一个很好的评论。在上面的示例中,我使用了许多选项卡邮箱,您可以为每个用户邮箱选项卡视图使用本地事件总线。如果每个邮箱选项卡视图本身就非常复杂,包含许多嵌套的子视图和要生成/处理的大量事件,那么您可能希望这样做。