【问题标题】:Delegating events to sub-views in Backbone.js将事件委托给 Backbone.js 中的子视图
【发布时间】:2011-12-22 12:11:47
【问题描述】:

我们都知道这样做是不好的:

<ul>
  <li>Item</li>
  <li>Item</li>
  ... 500 more list items
</ul>

然后……

$("ul li").bind("click", function() { ... });

我一直在查看大量 Backbone 示例/指南,以下似乎是根据模型集合呈现包含项目的列表的标准方法。

var ListView = Backbone.View.extend() {

  tagName: 'ul',

  render: function() {
    this.collection.each(function(item) {
      var view = new ListItemView({model: item});
      $(this.el).append(view.render().el);
    });
    return this;
  }
});

列表项视图:

var ListItemView = Backbone.View.extend() {

  tagName: 'li',

  events: {
   'click' : 'log'
  }

  log : function() {
    console.log(this.model.get("title"));
  }

  render: function() {
    $(this.el).html(this.template(this.model.toJSON()));
    return this;
  }
});

如果我没记错的话,用一个包含 500 个模型的集合实例化 listView,会给我 500 个点击事件,每行一个。这很糟糕吧?

我知道 Backbone 已经为命名空间事件内置了事件委托:

events : {
  'click li' : 'log'
}

我想我可以把它放在我的 ListView 中,它只会为整个列表创建一个单击事件,但是我将无法访问与单击的列表项对应的模型数据。

主干开发人员使用什么模式来解决这个典型问题?

【问题讨论】:

    标签: javascript performance backbone.js


    【解决方案1】:

    Derick Bailey 写了一篇关于这个困境的详细博文,你可以在这里查看:http://lostechies.com/derickbailey/2011/10/11/backbone-js-getting-the-model-for-a-clicked-element/

    【讨论】:

    • 谢谢,这正是我正在寻找的那种讨论。
    【解决方案2】:

    您可以将实例与元素关联,如下所示:

    events : {
      'click li' : 'log'
    },
    
    log: function( e ) {
    var elm = e.currentTarget //Same as `this` in normally bound jQuery event
    
    
    jQuery.data( elm, "viewInstance" ).log( e );
    },
    

    然后:

    var ListItemView = Backbone.View.extend() {
    
      tagName: 'li',
    
      log : function() {
        console.log(this.model.get("title");
      }
    
      render: function() {
            //Associate the element with the instance
        $(this.el).html(this.template(this.model.toJSON())).data( "viewInstance", this );
        return this;
      }
    });
    

    【讨论】:

    • 感谢您的回复。到目前为止,这是我为了解决这个问题而不得不做的事情,但话又说回来,它使用 jQuery 在 DOM 中存储数据,从长远来看,这并不是一种非常干净的方法。跨度>
    • @Daniel jQuery 不会将数据存储在 DOM 中,而是将其存储在常规 js 对象 (jQuery.cache) 中。无论如何,jQuery 也会在内部污染任何具有带有 expando 属性的事件的元素,之后在元素上执行 data 除了在常规 js 对象中添加更多属性之外没有任何效果。
    • @Daniel 是的,将事件绑定到每个元素没有任何意义,这与在每个元素上使用 jQuery.data + 将本机事件绑定到每个元素相同。您可以通过完全不使用 jQuery 来绑定事件来避免这种情况,但它真的比使用 DOM 数据更好吗? :P
    【解决方案3】:

    从父视图跟踪子视图。然后在添加子视图时将其添加到哈希中,并将 cid 添加到子视图的 el 中。这种方式有一个指向子视图的指针,并且可以对其模型等执行操作......

    我没有在下面测试过这个确切的代码,所以这可能有一两个地方是错误的,但我已经测试了这个一般原则。我也省略了 listitemview 代码。

    var ListView = Backbone.View.extend() {
      subViews: {},
      tagName: 'ul',
      events: {
        'click li' : 'clickItem'
      },
      clickItem: function(event){
         var id = event.currentTarget.cid;
         var subView = this.subViews[id];
    
    
      },
      render: function() {
    
        this.collection.each(function(item) {
          var view = new ListItemView({model: item});
          this.subViews[view.cid] = view;
          subEl = view.render().el;
          subEl.cid = view.cid;
          $(this.el).append(subEl);
        });
        return this;
      }
    });
    

    【讨论】:

      猜你喜欢
      • 2012-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多