掌握一个 MVC 框架,最关键的一节就是掌握如何在各个 View 之间通讯。以前用 Angular 时,以为基于事件的通讯方式 ($on, $emit, $boardcast) 或者 基于 service 的方式都很是好用。转战 Backbone 以后,因为对 Backbone 的事件机制理解不够且使用很是灵活,一直没找到一个好的通讯方式。直到看见这篇文章,做者经过一个简单的例子,层层深刻,把 Backbone View 之间通讯的三种方式讲的清晰明了。译文以下(已拿到受权):javascript
我正在开发的这个网页主要有两部分,分别是 document 和 sidebar。html
如上图所示,我设立了三个视图 (view) :java
ApplicationView
- 做为最外层视图来包含下级视图DocumentView
- 展现正在编辑或浏览的内容SidebarView
- 展现一些和 document 相关的信息react
DocumentView
和 SidebarView
做为 ApplicationView
的子视图,因此总体的视图结构以下图所示:app
用户在任意一个子视图进行操做,另外一个子视图都须要随之变化。但因为两个子视图之间并不能直接通知对方(也就是说,它们的做用域没有直接联系,不像父视图,能够包含它全部子视图的做用域),因此,我须要一个事件机制。框架
在我谷歌和参考其余人的方法以后,我总结出了以下三种不一样的通讯方式。ide
我经过父视图 (ApplicationView
) 来为它的两个子视图传递事件。由于父视图包含它全部子视图的做用域,所以用它做为事件传递的媒介最好不过。函数
JavaScript 代码以下:this
javascript
var ApplicationView = Backbone.View.extend({ initialize : function(){ this.documentView = new DocumentView({parent:this}); this.sidebarView = new SidebarView({parent:this}); this.documentView.on('edit', this.documentEdited, this); }, documentEdited : function(){ // do some stuff this.sidebarView.trigger('documentEdit'); } }); var DocumentView = Backbone.View.extend({ onEdit : function(){ this.trigger('edit'); } }); var SidebarView = Backbone.View.extend({ initialize : function(){ this.on('documentEdit', this.onDocumentEdit, this); }, onDocumentEdit : function(){ // react to document edit. } });
可是,这种方法并不高效。由于我须要在 ApplicationView
中添加一个额外的事件处理函数 documentEdited()
。若是子视图有一堆事件传过来,则在父视图中会不断触发事件处理函数,致使它不堪重负。spa
那么来看看第二种方法。
我经过继承 Backbone.Events 来建立一个全局对象 EventBus
。把它注入到各个子视图中,用来广播事件。
JavaScript 代码以下:
javascript
var ApplicationView = Backbone.View.extend({ initialize : function(){ this.eventBus = _.extend({}, Backbone.Events); this.documentView = new DocumentView({ eventBus : this.eventBus }); this.sidebarView = new SidebarView({ eventBus : this.eventBus }); }, }); var DocumentView = Backbone.View.extend({ initialize : function(options){ this.eventBus = options.eventBus; }, onEdit : function(){ this.eventBus.trigger('documentEdit'); } }); var SidebarView = Backbone.View.extend({ initialize : function(options){ this.eventBus = options.eventBus; this.eventBus.on('documentEdit', this.onDocumentEdit, this); }, onDocumentEdit : function(){ // react to document edit. } });
在这个方法中,我把 EventBus
做为一个全局对象用来注册事件。若是我想在各个视图之间通讯,只须要在视图中注入 EventBus
,就能够经过它方便地触发或监听事件了。
注意:若是你不想要建立全局对象,你仍然能够建立模块 (module) 或视图 (view) 级别的 EventBus
用来通讯。
这个方法已经明显优于第一种方法了。可是须要咱们手动的在子视图中引入 EventBus
,说明还有能够改进的空间,那么,来看看第三种方法。
在第二种方法中,我建立了一个单独的 EventBus
,继承自 Backbone.Events
。但最近我悟到 Backbone
对象自己就是一个混合了 Events
的对象,因此我直接用 Backbone
广播事件,就无需单另建立的 EventBus
了。
并且 Backbone 对象能够直接调用,这样我就没必要在每一个子视图中手动注入它了。
JavaScript 代码以下:
javascriptvar ApplicationView = Backbone.View.extend({ initialize : function(){ this.documentView = new DocumentView(); this.sidebarView = new SidebarView(); }, }); var DocumentView = Backbone.View.extend({ onEdit : function(){ Backbone.trigger('documentEdit'); } }); var SidebarView = Backbone.View.extend({ initialize : function(options){ Backbone.on('documentEdit', this.onDocumentEdit, this); }, onDocumentEdit : function(){ // react to document edit. } });
我最终在个人项目中使用了第三种方法。并且在我看来,虽然它直接依赖了全局的 Backbone
对象,可是用起来却异常简洁。
若是有比这更好的方法,欢迎分享交流。
(译文完)
原文地址:Communicating between views in Backbone
译文地址:Backbone View 之间通讯的三种方式