3

假设我有一些项目要显示在列表中。该列表有一个将所有项目聚合为项目视图的视图。现在我想处理项目视图上的点击事件,并将处理委托给列表视图。

让我们看一些示例代码:

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
    }
});

每当必须处理任何类型的列表视图时,这是一种非常通用的模式。

我通过初始化时在项目上设置的数据属性将项目视图返回到处理程序中。我需要获取项目视图,因为作为处理单击事件的一部分,我想要对项目执行的任何操作都基于视图。

另请注意,我使用的closest是因为项目视图可能很复杂,并且单击事件的实际目标可能是根元素的后代。

所以问题是:这种通过data属性将视图绑定到其根元素的方法是否正确——尤其是在考虑垃圾收集和内存泄漏时?还有比这更好的吗?

4

1 回答 1

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事件代表一些“更高级别”的操作,例如selector activate,您应该这样命名您的自定义事件。通过这种方式,您可以在视图之间创建一个合乎逻辑的、健壮的接口,而无需考虑父ListView级及其子级的实现细节。只ItemView应该知道它是否被点击、悬停、双击等。

于 2013-02-19T15:21:16.650 回答