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