Answers:
一种方法是:
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'
}
});
检查事件是函数还是对象
var ChildView = ParentView.extend({
events: function(){
var parentEvents = ParentView.prototype.events;
if(_.isFunction(parentEvents)){
parentEvents = parentEvents();
}
return _.extend({},parentEvents,{
'click' : 'onclickChild'
});
}
});
parentEvents = _.result(ParentView.prototype, 'events');
而不是“手动”检查是否events
为函数。
_.result
,我以前没有注意到。对于任何有兴趣的人,这里都是jsfiddle,该主题上有很多变种:jsfiddle
this
与必须通过实例名称调用父类。非常感谢你。
士兵。蛾的答案是一个很好的答案。进一步简化它,您可以执行以下操作
var ChildView = ParentView.extend({
initialize: function(){
_.extend(this.events, ParentView.prototype.events);
}
});
然后只需以典型方式在任一类中定义事件。
this.events
&ParentView.prototype.events
否则,如果两个都在同一事件上定义处理程序,则父级的处理程序将覆盖子级的处理程序。
{},ParentView.prototype.events,this.events
delegateEvents
在构造函数中被称为绑定事件。因此,当您在中扩展它时initialize
,为什么还不算太晚呢?
initialize
在少数情况下进行编写(然后也不得不处理该函数的层次结构),仅仅是为了合并事件对象。对我来说似乎更干净,可以保持events
合并。话虽如此,我不会想到这种方法,被迫以另一种方式看待事物总是很高兴的:)
从Backbone.View创建专门的基础构造函数来处理层次结构中的事件继承会更容易。
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
}
这样,每当我们使用重新定义的扩展函数创建新的“子类”(子构造函数)时,都可以减少(合并)事件在层次结构中的哈希。
# 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: ....
}
通过创建专门的视图:重新定义扩展功能的BaseView,我们可以拥有想要继承其父视图的声明事件的子视图(如AppView,SectionView),只需从BaseView或其派生对象中扩展一个子视图即可。
我们避免了在子视图中以编程方式定义事件函数的需要,在大多数情况下,子视图需要显式地引用父构造函数。
这也将起作用:
class ParentView extends Backbone.View
events: ->
'foo' : 'doSomething'
class ChildView extends ParentView
events: ->
_.extend({}, _.result(_super::, 'events') || {},
'bar' : 'doOtherThing')
使用Straight super
不适用于我,或者是手动指定ParentView
或继承的类。
访问_super
任何coffeescript中可用的varClass … 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 */ }
});
对于Backbone 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",
}
我发现这更有趣的解决方案的文章
它使用了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和attribute进行操作。
此示例不涉及由函数设置的属性,但是本文的作者提供了这种情况下的解决方案。
要完全在父类中做到这一点并在子类中支持基于函数的事件哈希,以便子代可以MyView.prototype.initialize
忽略继承(如果子代重写,则子代必须调用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);
};
}
});
如果您确定ParentView
将事件定义为object并且不需要动态定义事件ChildView
,则可以通过取消使用函数并_.extend
直接使用来进一步简化Solder.moth的答案:
var ParentView = Backbone.View.extend({
events: {
'click': 'onclick'
}
});
var ChildView = ParentView.extend({
events: _.extend({}, ParentView.prototype.events, {
'click' : 'onclickChild'
})
});
我喜欢的一种模式是修改构造函数并添加一些其他功能:
// 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'
});
}
});
我更喜欢这种方法,因为您不必标识父级-要更改的变量要少一些。我对attributes
和使用相同的逻辑defaults
。
哇,这里有很多答案,但我想我会再提供一个。如果使用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
extend2
)是我能想到的最好的方法,并且我认为这并不是那么糟糕:习惯于Backbone的任何人都已经习惯了使用extend
,因此,这种方式他们不需要记住一个新命令。