假设我有一些项目要显示在列表中。该列表具有将所有项目聚合为项目视图的视图。现在我想处理项目视图上的点击事件,并将处理委托给列表视图。
让我们看一些示例代码:
ItemView = Backbone.View.extend({
className: 'item',
initialize: function() {
this.$el.data('backbone-view', this);
}
});
请注意,我将视图对象本身作为根元素的属性附加,这实际上为视图和元素创建了一个循环引用情形。
ListView = Backbone.View.extend({
initialize: function() {
// contains the item views
this.items = [];
// click event delegation
this.$el.click(_.bind(this._onClick, this));
},
addItem: function(v) {
if ( !(v instanceof ItemView) ) return;
this.items.push(v);
this.$el.append(v.el);
},
_onClick: function(e) {
var el = $(e.target).closest('.item'),
view = el.data('backbone-view');
// do something with the view
}
});
每当必须处理任何类型的列表视图时,这是一种非常通用的模式。
我通过我在初始化时间项目上设置的data属性在处理程序中获取项目视图。我需要获取项目视图,因为我想在项目上执行的任何操作都是基于视图的。
另请注意,我使用的是closest
,因为项目视图可能很复杂,而click事件的实际目标可能是根元素的后代。
所以问题:这是通过data
属性将视图绑定到它的根元素的正确方法 - 特别是在考虑垃圾收集和内存泄漏时?能有更好的东西吗?
答案 0 :(得分:1)
您应该在子视图中捕获事件。在我看来,任何Backbone视图都应该只处理其元素及其子元素的DOM事件。如果视图是嵌套的,那么最具体的视图应该处理事件。
如果要将处理委托给父视图,可以在ItemView
中触发骨干事件,并听取ListView
中的那些事件。
ItemView = Backbone.View.extend({
events: {
"click":"onClick"
},
onClick: function() {
//trigger a custom event, passing the view as first argument
this.trigger('click', this);
}
});
ListView = Backbone.View.extend({
addItem: function(v) {
if ( !(v instanceof ItemView) ) return;
//listen to custom event
this.listenTo(v, 'click', this._onClick);
this.items.push(v);
this.$el.append(v.el);
},
_onClick:function(itemView) {
//...
}
});
如果click
事件代表某些“更高级别”操作,例如select
或activate
,则应将自定义事件命名为此类。这样,您可以在视图之间创建一个逻辑的,健壮的接口,而不必将父ListView
与其子项的实现细节相关联。只有ItemView
才能知道它是否已被点击,悬停,双击等。