Backbone View 之间通讯的三种方式

掌握一个 MVC 框架,最关键的一节就是掌握如何在各个 View 之间通讯。以前用 Angular 时,以为基于事件的通讯方式 ($on, $emit, $boardcast) 或者 基于 service 的方式都很是好用。转战 Backbone 以后,因为对 Backbone 的事件机制理解不够且使用很是灵活,一直没找到一个好的通讯方式。直到看见这篇文章,做者经过一个简单的例子,层层深刻,把 Backbone View 之间通讯的三种方式讲的清晰明了。译文以下(已拿到受权):javascript


我正在开发的这个网页主要有两部分,分别是 document 和 sidebar。html

Backbone Application

如上图所示,我设立了三个视图 (view) :java

ApplicationView - 做为最外层视图来包含下级视图
DocumentView - 展现正在编辑或浏览的内容
SidebarView - 展现一些和 document 相关的信息react

DocumentViewSidebarView 做为 ApplicationView 的子视图,因此总体的视图结构以下图所示:app

Backbone View Structure

用户在任意一个子视图进行操做,另外一个子视图都须要随之变化。但因为两个子视图之间并不能直接通知对方(也就是说,它们的做用域没有直接联系,不像父视图,能够包含它全部子视图的做用域),因此,我须要一个事件机制。框架

在我谷歌和参考其余人的方法以后,我总结出了以下三种不一样的通讯方式。ide

1. 经过父视图传递事件

我经过父视图 (ApplicationView) 来为它的两个子视图传递事件。由于父视图包含它全部子视图的做用域,所以用它做为事件传递的媒介最好不过。函数

Backbone View Event Relay

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

那么来看看第二种方法。

2. 经过 EventBus 在视图间通讯

我经过继承 Backbone.Events 来建立一个全局对象 EventBus。把它注入到各个子视图中,用来广播事件。

Backbone Views Event Bus

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,说明还有能够改进的空间,那么,来看看第三种方法。

3. 直接用 Backbone 做为事件注册机

在第二种方法中,我建立了一个单独的 EventBus,继承自 Backbone.Events。但最近我悟到 Backbone 对象自己就是一个混合了 Events 的对象,因此我直接用 Backbone 广播事件,就无需单另建立的 EventBus 了。

并且 Backbone 对象能够直接调用,这样我就没必要在每一个子视图中手动注入它了。

Backbone as EventBus

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 之间通讯的三种方式

相关文章
相关标签/搜索