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 之間通訊的三種方式

相關文章
相關標籤/搜索