javascript 将事件委托给 Backbone 中的父视图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10485610/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Delegating events to a parent view in Backbone
提问by wheresrhys
My view, TuneBook
, has several child views of type ClosedTune
. I also have separate full page views for each tune, OpenTune
. The same events are bound within ClosedTune
and OpenTune
, so I've designed my app so that they both inherit from a shared 'abstract' view Tune
.
我的视图 ,TuneBook
有几个类型为 的子视图ClosedTune
。对于每首曲子,我也有单独的完整页面视图OpenTune
。ClosedTune
和中绑定了相同的事件OpenTune
,因此我设计了我的应用程序,以便它们都继承自共享的“抽象”视图Tune
。
To make my app more scaleable I would like the events for each ClosedTune
to be delegated to TuneBook
, but for maintainability I would like the same handlers (the ones stored in Tune
) to be used by TuneBook
(although they'd obviously need to be wrapped in some function).
为了使我的应用程序更具可扩展性,我希望将每个事件的事件ClosedTune
委托给TuneBook
,但为了可维护性,我希望使用相同的处理程序(存储在 中的处理程序Tune
)TuneBook
(尽管它们显然需要包含在某些函数中)。
The problem I have is, within TuneBook
, finding the correct ClosedTune
to call the handler on. What's a good way to architect this, or are there other good solutions for delegating events to a parent view?
我遇到的问题是,在 内TuneBook
找到ClosedTune
调用处理程序的正确方法。什么是构建此架构的好方法,或者是否有其他好的解决方案将事件委托给父视图?
Note- not a duplicate of Backbone View: Inherit and extend events from parent(which is about children inheriting from a parent class, whereas I'm asking about children which are child nodes of the parent in the DOM)
注意- 不是Backbone View: Inherit and extend events from parent(这是关于从父类继承的子类,而我询问的是 DOM 中父类的子节点的子节点)
回答by ggozad
In your parent view (extending also from Backbone.Events
), I would bind onEvent
to the DOM event. On trigger, it would fire a backbone event including some "id" attribute that your child views know (presumably some row id?).
在您的父视图中(也从 扩展Backbone.Events
),我将绑定onEvent
到 DOM 事件。触发时,它会触发一个主干事件,包括您的子视图知道的一些“id”属性(大概是某个行 ID?)。
var TuneBook = Backbone.View.extend(_.extend({}, Backbone.Events, {
events: {
"click .tune .button": "clickHandler"
},
clickHandler: function (ev) {
this.trigger('buttonClick:' + ev.some_id_attr, ev);
},
}));
Child views would then naturally subscribe to the parent views event that concerns them. Below I do it in initialize
passing the parent view as well as that special id attribute you used before in options
.
然后子视图自然会订阅与它们相关的父视图事件。下面我initialize
通过传递父视图以及您之前在options
.
var ClosedTune = Backbone.View.extend({
initialize: function (options) {
options.parent.on('buttonClick:' + options.id, this.handler, this);
},
handler: function (ev) {
...
},
});
You can of course also set up similar subscribers on Tune
or OpenTune
.
您当然也可以在Tune
或上设置类似的订阅者OpenTune
。
回答by JMM
Here are a couple of possibilities.
这里有几种可能性。
1. Centralized: store ClosedTune
objects in the TuneBook
instance
1.集中式:将ClosedTune
对象存储在TuneBook
实例中
Store a reference to each
ClosedTune
intune_book.tunes
. How you populatetune_book.tunes
is up to you; since you mentioned an adder method onTuneBook
, that's what I've illustrated below.In the
TuneBook
event handler, retrieve theClosedTune
fromtune_book.tunes
by using something like theid
attribute of the event target as the key. Then call theTune
orClosedTune
handler.
店里每一个参考
ClosedTune
在tune_book.tunes
。您如何填充tune_book.tunes
取决于您;既然您提到了 上的加法器方法TuneBook
,这就是我在下面说明的内容。在
TuneBook
事件处理程序中,通过使用诸如事件目标的属性之类的东西作为键来检索ClosedTune
from 。然后调用or处理程序。tune_book.tunes
id
Tune
ClosedTune
var Tune = Backbone.View.extend({
className: "tune",
click_handler: function (event) {
event.preventDefault();
console.log(this.id + " clicked");
},
render: function () {
this.$el.html(
'<a href="" class="button">' + this.id + '</a>'
);
return this;
}
});
var ClosedTune = Tune.extend({});
var OpenTune = Tune.extend({
events: {
"click .button" : 'click_handler'
}
});
var TuneBook = Backbone.View.extend({
events: {
"click .tune .button" : 'click_handler'
},
click_handler: function (event) {
var tune = this.options.tunes[
$(event.target).closest(".tune").attr('id')
];
tune.click_handler( event );
},
add_tune: function (tune) {
this.options.tunes[tune.id] = tune;
this.$el.append(tune.render().el);
},
render: function () {
$("body").append(this.el);
return this;
}
});
var tune_book = new TuneBook({
tunes: {}
});
[1, 2, 3].forEach(function (number) {
tune_book.add_tune(new ClosedTune({
id: "closed-tune-" + number
}));
});
tune_book.render();
var open_tune = new OpenTune({
id: "open-tune-1"
});
$("body").append(open_tune.render().el);
2. Decentralized: associate the view object with the DOM object using jQuery.data()
2. 去中心化:将视图对象与 DOM 对象关联使用 jQuery.data()
When you create a
ClosedTune
, store a reference to it, e.g.this.$el.data('view_object', this)
.In the event listener, retrieve the
ClosedTune
, e.g.$(event.target).data('view_object')
.
创建 时
ClosedTune
,请存储对它的引用,例如this.$el.data('view_object', this)
.在事件侦听器中,检索
ClosedTune
,例如$(event.target).data('view_object')
。
You can use the same exact handler for ClosedTune
(in TuneBook
) and OpenTune
, if you want.
如果需要,您可以对ClosedTune
(in TuneBook
) 和使用完全相同的处理程序OpenTune
。
var Tune = Backbone.View.extend({
className: "tune",
initialize: function (options) {
this.$el.data('view_object', this);
},
click_handler: function (event) {
event.preventDefault();
var tune =
$(event.target).closest(".tune").data('view_object');
console.log(tune.id + " clicked");
},
render: function () {
this.$el.html(
'<a href="" class="button">' + this.id + '</a>'
);
return this;
}
});
var ClosedTune = Tune.extend({
initialize: function (options) {
this.constructor.__super__.initialize.call(this, options);
}
});
var OpenTune = Tune.extend({
events: {
"click .button" : 'click_handler'
}
});
var TuneBook = Backbone.View.extend({
events: {
"click .tune .button": Tune.prototype.click_handler
},
add_tune: function (tune) {
this.$el.append(tune.render().el);
},
render: function () {
$("body").append(this.el);
return this;
}
});
var tune_book = new TuneBook({
tunes: {}
});
[1, 2, 3].forEach(function (number) {
tune_book.add_tune(new ClosedTune({
id: "closed-tune-" + number
}));
});
tune_book.render();
var open_tune = new OpenTune({
id: "open-tune-1"
});
$("body").append(open_tune.render().el);
Response to comment
回复评论
I considered option 1 but decided against it as I already have a collection of tune models in the tunebook and didn't want another object I'd need to keep in sync
我考虑了选项 1,但决定反对它,因为我已经在 tunebook 中收集了一组调谐模型并且不想要另一个我需要保持同步的对象
I guess it depends what kind of housekeeping / syncing you feel the need to do, and why.
我想这取决于您觉得需要做什么样的内务管理/同步,以及为什么。
(e.g. in TuneModel.remove() I would need to remove the view from tunebook's list of views... would probably need events to do this, so an event only solution starts to look more attractive).
(例如,在 TuneModel.remove() 中,我需要从 tunebook 的视图列表中删除视图......可能需要事件来执行此操作,因此仅事件解决方案开始看起来更具吸引力)。
Whydo you feel that you "need to remove the view from tunebook's list of views"? (I'm not suggesting you shouldn't, just asking why youwant to.) Since you do, how do you think @ggozad's approach differs in that respect?
为什么您觉得您“需要从 tunebook 的视图列表中删除该视图”?(我并不是建议您不应该这样做,只是问您为什么要这样做。)既然您这样做了,那么您认为 @ggozad 的方法在这方面有何不同?
Both techniques store ClosedTune
objects in the TuneBook
instance. In @ggozad's technique it's just hidden behind an abstraction that perhaps makes it less obvious to you.
这两种技术都ClosedTune
在TuneBook
实例中存储对象。在@ggozad 的技术中,它只是隐藏在一个抽象之后,这可能会使您不那么明显。
In my example they're stored in a plain JS object (tune_book.tunes
). In @ggozad's they're stored in the _callbacks
structure used by Backbone.Events
.
在我的示例中,它们存储在一个普通的 JS 对象 ( tune_book.tunes
) 中。在@ ggozad就是他们存储在_callbacks
所用的结构Backbone.Events
。
Adding a ClosedTune
:
添加一个ClosedTune
:
1.
1.
this.options.tunes[tune.id] = tune;
2.
2.
this.on('buttonClick:' + tune.id, tune.handler, tune);
If you want to get rid of a ClosedTune
(say you remove it from the document with tune.remove()
and you want the view object gone completely), using @ggozad's approach will leave an orphaned reference to the ClosedTune
in tune_book._callbacks
unless you perform the same kind of housekeeping that would make sense with the approach I suggested:
如果你想摆脱一个ClosedTune
(假设你从文档中删除它tune.remove()
并且你希望视图对象完全消失),使用@ggozad 的方法将留下对ClosedTune
in的孤立引用,tune_book._callbacks
除非你执行相同类型的内务处理我建议的方法的意义:
1.
1.
delete this.options.tunes[tune.id];
tune.remove();
2.
2.
this.off("buttonClick:" + tune.id);
tune.remove();
The first line of each example is optional -- depending if you want to clean up the ClosedTune
objects or not.
每个示例的第一行都是可选的——取决于您是否想要清理ClosedTune
对象。
Option 2 is more or less what I'm doing right now, but (for other reasons) I also store the model as a data attribute on view.$el, and I can't help feeling that there's got to be a better way than storing references all over the place.
选项 2 或多或少是我现在正在做的,但是(出于其他原因)我还将模型作为数据属性存储在 view.$el 上,我不禁觉得必须有更好的方法而不是到处存储引用。
Well, it ultimately comes down to your preference for how to structure things. If you prefer storing the view objects in a more centralized fashion, you can store them in the TuneBook
instance instead of using jQuery.data
. See #1: Centralized.
好吧,这最终归结为您对如何构建事物的偏好。如果您更喜欢以更集中的方式存储视图对象,则可以将它们存储在TuneBook
实例中而不是使用jQuery.data
. 参见 #1:集中式。
One way or another you're storing references to the ClosedTune
objects: using jQuery.data
, or in a plain object in the TuneBook
, or in _callbacks
in the TuneBook
.
拉上你存储引用的ClosedTune
对象:使用jQuery.data
,或在一个普通的对象TuneBook
,或_callbacks
在TuneBook
。
If you like @ggozad's approach for reasons that you understand, go for it, but it's not magic. As it's presented here I'm not sure what advantage is supposed to be provided by the extra level of abstraction compared to the more straightforward version I present in #1. If there is some advantage, feel free to fill me in.
如果您出于您理解的原因喜欢@ggozad 的方法,那就去做吧,但这并不神奇。正如这里介绍的那样,与我在 #1 中介绍的更直接的版本相比,我不确定额外的抽象级别应该提供什么优势。如果有什么优势,请随时填写我。
回答by Shahar Shokrani
Great solution I have taken from this article(@dave-cadwallader comment).
我从这篇文章中得到了很好的解决方案(@dave-cadwallader 评论)。
Extend an general backbone events object and store it in a reference vent
:
扩展通用主干事件对象并将其存储在引用中vent
:
var vent = _.extend({}, Backbone.Events);
Pass it to parent view:
将其传递给父视图:
var parentView = new ParentView({vent: vent});
The child view will trigger an event:
子视图会触发一个事件:
ChildView = Backbone.View.extend({
initialize: function(options){
this.vent = options.vent;
},
myHandler: function(){
this.vent.trigger("myEvent", this.model);
}
});
And the parent view is listening to the child event:
并且父视图正在侦听子事件:
ParentView = Backbone.View.extend({
initialize: function(options){
this.vent = options.vent;
this.vent.on("myEvent", this.onMyEvent);
let childView = new ChildView({vent: this.vent});
},
onMyEvent: function(){
console.log("Child event has been ");
}
});
Disclaimer - pay attention that the vent
object has to be injected to every view so you will find in this article better design patterns to make use of.
免责声明 - 请注意,必须将vent
对象注入到每个视图中,因此您会在本文中找到更好的设计模式来使用。