骨干视图:inheritance和扩展来自父母的事件

骨干的文档指出:

events属性也可以定义为一个返回事件散列的函数,以便以编程方式定义事件,以及从父视图inheritance它们。

你如何inheritance父母的视图事件并扩展它们?

父视图

var ParentView = Backbone.View.extend({ events: { 'click': 'onclick' } }); 

儿童视图

 var ChildView = ParentView.extend({ events: function(){ ???? } }); 

一种方法是:

 var ChildView = ParentView.extend({ events: function(){ return _.extend({},ParentView.prototype.events,{ 'click' : 'onclickChild' }); } }); 

另一个将是:

 var ParentView = Backbone.View.extend({ originalEvents: { 'click': 'onclick' }, //Override this event hash in //a child view additionalEvents: { }, events : function() { return _.extend({},this.originalEvents,this.additionalEvents); } }); var ChildView = ParentView.extend({ additionalEvents: { 'click' : ' onclickChild' } }); 

检查事件是function还是对象

 var ChildView = ParentView.extend({ events: function(){ var parentEvents = ParentView.prototype.events; if(_.isFunction(parentEvents)){ parentEvents = parentEvents(); } return _.extend({},parentEvents,{ 'click' : 'onclickChild' }); } }); 

士兵。很好的答案是。 简化它可以进一步你可以做到以下几点

 var ChildView = ParentView.extend({ initialize: function(){ _.extend(this.events, ParentView.prototype.events); } }); 

然后,只需以典型的方式在任一课程中定义您的活动。

您也可以使用defaults方法避免创build空对象{}

 var ChildView = ParentView.extend({ events: function(){ return _.defaults({ 'click' : 'onclickChild' }, ParentView.prototype.events); } }); 

如果您使用CoffeeScript并为events设置function,则可以使用super

 class ParentView extends Backbone.View events: -> 'foo' : 'doSomething' class ChildView extends ParentView events: -> _.extend {}, super, 'bar' : 'doOtherThing' 

从Backbone.View创build专门的基础构造函数不是更容易,它处理层次结构中事件的inheritance。

 BaseView = Backbone.View.extend { # your prototype defaults }, { # redefine the 'extend' function as decorated function of Backbone.View extend: (protoProps, staticProps) -> parent = this # we have access to the parent constructor as 'this' so we don't need # to mess around with the instance context when dealing with solutions # where the constructor has already been created - we won't need to # make calls with the likes of the following: # this.constructor.__super__.events inheritedEvents = _.extend {}, (parent.prototype.events ?= {}), (protoProps.events ?= {}) protoProps.events = inheritedEvents view = Backbone.View.extend.apply parent, arguments return view } 

这允许我们使用重定义的扩展函数创build一个新的“子类”(子构造函数)时,减less(合并)层次结构中的事件。

 # AppView is a child constructor created by the redefined extend function # found in BaseView.extend. AppView = BaseView.extend { events: { 'click #app-main': 'clickAppMain' } } # SectionView, in turn inherits from AppView, and will have a reduced/merged # events hash. AppView.prototype.events = {'click #app-main': ...., 'click #section-main': ... } SectionView = AppView.extend { events: { 'click #section-main': 'clickSectionMain' } } # instantiated views still keep the prototype chain, nothing has changed # sectionView instanceof SectionView => true # sectionView instanceof AppView => true # sectionView instanceof BaseView => true # sectionView instanceof Backbone.View => also true, redefining 'extend' does not break the prototype chain. sectionView = new SectionView { el: .... model: .... } 

通过创build一个专门的视图:重新定义扩展函数的BaseView,我们可以通过从BaseView或其衍生产品扩展来实现想要inheritance其父视图声明事件的子视图(如AppView,SectionView)。

我们避免了在我们的子视图中以编程方式定义我们的事件函数的需求,在大多数情况下需要明确地引用父构造函数。

@ soldier.moth最后build议的简短版本:

 var ChildView = ParentView.extend({ events: function(){ return _.extend({}, _.result(ParentView.prototype, 'events') || {}, { 'click' : 'onclickChild' }); } }); 

这也将工作:

 class ParentView extends Backbone.View events: -> 'foo' : 'doSomething' class ChildView extends ParentView events: -> _.extend({}, _.result(_super::, 'events') || {}, 'bar' : 'doOtherThing') 

使用直super不工作对我来说,要么是手动指定ParentView或inheritance类。

访问可在任何coffeescript Class … extends …使用的_super var Class … extends …

 // ModalView.js var ModalView = Backbone.View.extend({ events: { 'click .close-button': 'closeButtonClicked' }, closeButtonClicked: function() { /* Whatever */ } // Other stuff that the modal does }); ModalView.extend = function(child) { var view = Backbone.View.extend.apply(this, arguments); view.prototype.events = _.extend({}, this.prototype.events, child.events); return view; }; // MessageModalView.js var MessageModalView = ModalView.extend({ events: { 'click .share': 'shareButtonClicked' }, shareButtonClicked: function() { /* Whatever */ } }); // ChatModalView.js var ChatModalView = ModalView.extend({ events: { 'click .send-button': 'sendButtonClicked' }, sendButtonClicked: function() { /* Whatever */ } }); 

对于骨干版本1.2.3, __super__工作正常,甚至可能被链接。 例如:

 // A_View.js var a_view = B_View.extend({ // ... events: function(){ return _.extend({}, a_view.__super__.events.call(this), { // Function - call it "click .a_foo": "a_bar", }); } // ... }); // B_View.js var b_view = C_View.extend({ // ... events: function(){ return _.extend({}, b_view.__super__.events, { // Object refence "click .b_foo": "b_bar", }); } // ... }); // C_View.js var c_view = Backbone.View.extend({ // ... events: { "click .c_foo": "c_bar", } // ... }); 

…其中 – 在A_View.js – 将导致:

 events: { "click .a_foo": "a_bar", "click .b_foo": "b_bar", "click .c_foo": "c_bar", } 

我在本文中find了更有趣的解决scheme

它使用Backbone的super和ECMAScript的hasOwnProperty。 其进步的第二个例子就像一个魅力。 这是一个代码:

 var ModalView = Backbone.View.extend({ constructor: function() { var prototype = this.constructor.prototype; this.events = {}; this.defaultOptions = {}; this.className = ""; while (prototype) { if (prototype.hasOwnProperty("events")) { _.defaults(this.events, prototype.events); } if (prototype.hasOwnProperty("defaultOptions")) { _.defaults(this.defaultOptions, prototype.defaultOptions); } if (prototype.hasOwnProperty("className")) { this.className += " " + prototype.className; } prototype = prototype.constructor.__super__; } Backbone.View.apply(this, arguments); }, ... }); 

你也可以为UI属性做到这一点。

这个例子没有考虑函数设置的属性,但是文章的作者在这种情况下提供了一个解决scheme。

这CoffeeScript解决scheme为我工作(并考虑到@ soldier.moth的build议):

 class ParentView extends Backbone.View events: -> 'foo' : 'doSomething' class ChildView extends ParentView events: -> _.extend({}, _.result(ParentView.prototype, 'events') || {}, 'bar' : 'doOtherThing') 

如果您确定ParentView将事件定义为对象,并且您不需要在ChildViewdynamic定义事件,则可以通过删除函数并直接使用_.extend来简化soldier.moth的答案:

 var ParentView = Backbone.View.extend({ events: { 'click': 'onclick' } }); var ChildView = ParentView.extend({ events: _.extend({}, ParentView.prototype.events, { 'click' : 'onclickChild' }) }); 

我喜欢的模式是修改构造函数并添加一些额外的function:

 // App View var AppView = Backbone.View.extend({ constructor: function(){ this.events = _.result(this, 'events', {}); Backbone.View.apply(this, arguments); }, _superEvents: function(events){ var sooper = _.result(this.constructor.__super__, 'events', {}); return _.extend({}, sooper, events); } }); // Parent View var ParentView = AppView.extend({ events: { 'click': 'onclick' } }); // Child View var ChildView = ParentView.extend({ events: function(){ return this._superEvents({ 'click' : 'onclickChild' }); } }); 

我更喜欢这种方法,因为您不必识别父variables,即可以更改一个variables。 我对attributesdefaults使用相同的逻辑。

哇,这里有很多答案,但我想我会再提供一个。 如果您使用BackSupport库,则它提供了extend2 。 如果使用extend2它会自动为您合并events (以及defaults和类似属性)。

这里有一个简单的例子:

 var Parent = BackSupport.View.extend({ events: { change: '_handleChange' } }); var Child = parent.extend2({ events: { click: '_handleClick' } }); Child.prototype.events.change // exists Child.prototype.events.click // exists 

https://github.com/machineghost/BackSupport

要完全在父类中执行此操作,并在子类中支持基于函数的事件散列,以便子代不能inheritance(如果覆盖initialize ,子代必须调用MyView.prototype.initialize ):

 var MyView = Backbone.View.extend({ events: { /* ... */ }, initialize: function(settings) { var origChildEvents = this.events; this.events = function() { var childEvents = origChildEvents; if(_.isFunction(childEvents)) childEvents = childEvents.call(this); return _.extend({}, : MyView.prototype.events, childEvents); }; } });