Backboneのドキュメンテーションの状態:
イベントプロパティは、イベントハッシュを返す関数として定義することもできます。これにより、プログラムでイベントを定義したり、親ビューからイベントを継承したりしやすくなります。
親のビューイベントをどのように継承して拡張しますか?
var ParentView = Backbone.View.extend({
events: {
'click': 'onclick'
}
});
var ChildView = ParentView.extend({
events: function(){
????
}
});
1つの方法は次のとおりです。
var ChildView = ParentView.extend({
events: function(){
return _.extend({},ParentView.prototype.events,{
'click' : 'onclickChild'
});
}
});
もう1つは:
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'
});
}
});
Soldier.mothの答えは良いものです。さらに単純化すると、次のことができます
var ChildView = ParentView.extend({
initialize: function(){
_.extend(this.events, ParentView.prototype.events);
}
});
次に、通常の方法でいずれかのクラスでイベントを定義します。
defaults
メソッドを使用して、空のオブジェクト{}
。
var ChildView = ParentView.extend({
events: function(){
return _.defaults({
'click' : 'onclickChild'
}, ParentView.prototype.events);
}
});
CoffeeScriptを使用し、関数をevents
に設定する場合、super
を使用できます。
class ParentView extends Backbone.View
events: ->
'foo' : 'doSomething'
class ChildView extends ParentView
events: ->
_.extend {}, super,
'bar' : 'doOtherThing'
階層の上のイベントの継承を処理する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: ....
}
拡張機能を再定義する特殊なビューを作成することにより、親ビューの宣言されたイベントを継承したいサブビュー(AppView、SectionViewなど)を作成できます。
サブビューでイベント関数をプログラムで定義する必要はありません。ほとんどの場合、明示的に親コンストラクターを参照する必要があります。
これも機能します:
class ParentView extends Backbone.View
events: ->
'foo' : 'doSomething'
class ChildView extends ParentView
events: ->
_.extend({}, _.result(_super::, 'events') || {},
'bar' : 'doOtherThing')
ストレートsuper
を使用しても機能しませんでした。手動でParentView
または継承クラスを指定していました。
任意のコーヒースクリプト_super
内で使用可能なClass … extends …
varへのアクセス
// 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 */ }
});
@ soldier.mothの最後の提案のショートバージョン:
var ChildView = ParentView.extend({
events: function(){
return _.extend({}, _.result(ParentView.prototype, 'events') || {}, {
'click' : 'onclickChild'
});
}
});
私はこれでより興味深い解決策を見つけました 記事
バックボーンsuperおよびECMAScriptのhasOwnPropertyを使用します。 2番目のプログレッシブの例は、魅力のように機能します。ここに少しコードがあります:
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およびattributesに対しても行うことができます。
この例では、関数によって設定されるプロパティは考慮しませんが、その場合の記事の著者が解決策を提供します。
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",
}
ParentView
にオブジェクトとして定義されたイベントがあり、ChildView
でイベントを動的に定義する必要がないと確信している場合は、関数と_.extend
を直接使用:
var ParentView = Backbone.View.extend({
events: {
'click': 'onclick'
}
});
var ChildView = ParentView.extend({
events: _.extend({}, ParentView.prototype.events, {
'click' : 'onclickChild'
})
});
うわー、ここにたくさんの答えがありますが、私はもう一つ提供するだろうと思いました。 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
これを完全に親クラスで行い、子クラスで関数ベースのイベントハッシュをサポートして、子が継承を認識できないようにします(子は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);
};
}
});
このCoffeeScriptソリューションは私のために働いた(そして@ soldier.mothの提案を考慮に入れている):
class ParentView extends Backbone.View
events: ->
'foo' : 'doSomething'
class ChildView extends ParentView
events: ->
_.extend({}, _.result(ParentView.prototype, 'events') || {},
'bar' : 'doOtherThing')
私が気に入っているこのパターンは、コンストラクタを変更し、いくつかの追加機能を追加することです。
// 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'
});
}
});
親を特定する必要がないため、この方法のほうが好ましいです。変更する変数が1つ少ないからです。 attributes
とdefaults
にも同じロジックを使用します。