2011-08-06 78 views
21

我有一個Backbone.View的通用子類,它有一個close事件偵聽器。Subclass a Backbone.View子類和保留事件

var GenericView = Backbone.View.extend({ 

    events : { 
     "click .close" : "close" 
    }, 

    close : function() { 
     console.log("closing view"); 
    } 

}); 

我想子類化這個泛型類並添加一些新的事件。但是,下面將覆蓋超類(上)事件對象。例如。

var ImplementedView = new GenericView({ 

    // setting this will stop 'close' in Super Class from triggering 
    events : { 
     "click .submit" : "submit" 
    } 

}); 

我應該如何創建一個子類,在這種情況下ImplementedView並保留事件?

我已經找到了一種方法來實現這一點,通過在構造子類時擴展事件對象。不過,我需要重新觸發this.delegateEvents(),我猜測這並不好。任何人可以對此發表評論嗎?

var ImplementedView = new GenericView({ 

    initialize : function (options) { 

     _.extend(this.events, { 
      "click .submit" : "submit" 
     }); 

     // re-attach events 
     this.delegateEvents(); 
    } 

}); 
+0

我可能是錯的,但我沒有看到你在任何地方繼承? ImplementedView只是一個引用GenericView實例的變量... – PhD

+0

您可能需要顯式使用'_.extend(...)'或者具有類似於視圖的'.extend'方法的功能... look通過backbone.js獲得線索。但是如果我是對的,那是因爲在原型鏈上缺乏顯式繼承。調用'this.delegateEvents()'或'Backbone.View.prototype.delegateEvents.call(events)'似乎是要走的路了 – PhD

+0

我會查看文檔。重新您的第一個評論:我沒有調用新的運營商,我雖然這是通過擴展Backbone.Model繼承? – Ross

回答

28

@Nupul是完全正確的:你沒有繼承你的GenericView

事實上,子類化在這裏並不是真正的詞,因爲JavaScript不會做經典的繼承。

因此,讓我們第一次嘗試和了解這裏發生了什麼:

var GenericView = Backbone.View.extend(propertiesObj, classPropertiesObj) 

Backbone.View是一個構造函數,當與new關鍵字調用,爲您創建一個新的對象。

由於這是JS,所有功能都真正發揮作用的對象,所以Backbone.View.extend只是掛Backbone.View,做了幾件事情的函數:

  1. 它設置了原型鏈,這樣你就可以訪問屬性和調用「基地」定義函數類
  2. 創建並返回一個新構造函數可以調用(這裏是GenericView)實例
  3. 將自身複製到被函數掛在你的繼承類的對象它返回的構造函數這樣你可以進一步繼承。

所以設置你想要的protoype鏈正確的方法是:

var ImplementedView = GenericView.extend({ 
    // implementation goes here 
}); 

和NOT:

var ImplementedView = new GenericView({//stuff}); 

,因爲這只是創建了一個GenericView的新實例。現在

,你還有一個問題,因爲當你做這樣的事情:

var impl_view = new ImplementedView; 

impl_view.events; // This isn't merged with the events you created 
        // for the GenericView 

在這一點上有不同的方式來得到你想要的結果,下面是一個使用delegateEvents種怎麼樣你沒有。順便說一句,使用它並不壞。

var GenericView = Backbone.View.extend({ 

    genericEvents: { 'click .close': 'close' }, 

    close: function() { console.log('closing view...'); } 

}); 

var ImplView = GenericView.extend({ 

    events: { 'click .submit': 'submit' }, 

    initialize: function(options) { 
    // done like this so that genericEvents don't overwrite any events 
    // we've defined here (in case they share the same key) 
    this.events = _.extend({}, this.genericEvents, this.events); 
    this.delegateEvents() 
    } 
}); 
+0

感謝您的詳細解答。 –

+2

這是一個很好的答案。 雖然缺點是必須在每個子視圖的init中粘貼:this.events = _.extend(this.genericEvents,this.events);'。但我想我可以處理。希望有一個更自動的方式。 –

+0

參數的順序在這一行上是倒退的'this.events = _.extend(this.genericEvents,this.events); ' 它實際上應該閱讀--' this.events = _.extend(this.events,this.genericEvents);'。第一個參數是目的地,第二個是源。 –

27

另一種選擇是使BaseView覆蓋Extend的實現。如:

var BaseView = Backbone.View.extend({ 
     //base view functionality if needed 
    }); 
BaseView.extend = function(child){ 
    var view = Backbone.View.extend.apply(this, arguments); 
    view.prototype.events = _.extend({}, this.prototype.events, child.events); 
    return view; 
}; 

這將自動擴展您的所有事件,以繼承BaseView的所有事件。

+0

集中行爲的好解決方案,而不像其他解決方案那樣分發。 – WiredPrairie

+0

非常好。在Backbone中,默認情況下是否有這個原因?也許他們不想重寫下劃線的extend()? – tybro0103

10

我喜歡剃鬚刀先生的解決方案,但對於較少侵入的東西:

var ChildView = ParentView.extend({ 
    events : _.extend({ 
     "change input": "handleInputChange" 
    }, ParentView.prototype.events) 
}); 

編輯:是的,你必須這樣做在每個子類中,但只需要幾個孩子時,它的有用,或者當你不控制父母「班級」時。

+0

但是這具有與每個子視圖複製和粘貼該代碼相同的問題。 –

+0

我喜歡使用'ParentView.prototype.events',而不是在父類上生成'genericEvents'。查看我的答案,瞭解如何在不復制/粘貼每個子視圖的情況下執行此操作。 – tybro0103

+0

同意,你的解決方案似乎更好...雖然,現在我想到了,不必擔心這些問題讓我感到不自在使用面向JS的OOP整體 –

3

這是一個很適合我的解決方案。您可以在父類和子類中使用events對象,而不必在每個子類中擴展它。只要在父類中擴展一次:

APP.Views.GenericWizard = Backbone.View.extend({ 
    events: { 
    'click .btn-prev' : function(){} 
    }, 
    initialize: function() { 
    _(this.events).extend(APP.Views.GenericWizard.prototype.events); 
    } 
}); 

APP.Views.RegisterWizard = APP.Views.GenericWizard.extend({ 
    events: { 
    'blur #username' : function(){} 
    }, 
}); 

var registerWizard = new APP.Views.RegisterWizard(); 
console.log(registerWizard.events); 
// Object {blur #username: function, click .btn-prev: function} 
+0

請解釋downvote的原因。這裏有什麼不對嗎? – tybro0103

+0

我認爲威爾剃鬚刀是最佳解決方案的正確軌道。如果我通過其他事件從RegisterWizard擴展會發生什麼?來自RegisterWizard的事件將會丟失。如果您要嘗試使用Javascript中的OOP,則必須考慮完整的原型鏈。真的沒有一個好的方法來做到這一點,但是,威爾再次可能是最乾淨和最準確的方法。 – Chris

+0

@克里斯,好點。我的方式只支持一個級別的子類。 – tybro0103