防止在骨干子视图中执行多个事件处理程序

时间:2013-07-30 11:29:24

标签: javascript jquery backbone.js backbone-views

我在Backbone中创建了一个视图(列表容器),它应包含多个视图项(部分)以及某些事件的处理。这种情况下的问题是事件的执行频率与子视图项放在容器内的频率相同。

我知道如果我将closeSection方法放入Container视图中,我可以阻止这种效果,但我认为这是一个错误的地方,专注于一个完整的工作视图。

在Backbone.js上下文中解决此问题的最佳解决方案是什么?

实施例

// The Container View (simplified)
var Container = Backbone.View.extend({
  el:$('#someDivContainer'),

  render:function(){
    $(this.el).html('<div id="head"></div><div id="sections"></div>');
    return this;
  }
});


// The subview (simplified)
var subView = backbone.View.extend({
  template:_template('<div><div class="scthd"><a class="op_cl">x</a></div><div><%- content %></div></div>');
  events:{
    'click a.op_cl':'closeSection'
  },

  initialize:function(){
    this.setElement($('#sections');
  },

  closeSection:function(event){
    event.preventDefault();
    console.log('event was triggered');
  },


  render:function(){
     $(this.el).append(this.template({content:'Test ' + i});
     return this;
  }
}); 

var oContainer = new Container();
    oContainer.render().el;


 // These produces a ten time event execution by a click on one a.op_cl item
 for(var i=0; i<10; i+=1){
   var oSubView = new subView();
       oSubView.render().el;
 }

“final”输出如下例所示:

<!-- The HTMl of the first view -->
<div id="head"></div>
<div id="sections">
  <div>
    <div class="scthd">
      <a class="op_cl">x</a>
    </div>
    <div>Test 0</div>
  </div>

  <div>
    <div class="scthd">
      <a class="op_cl">x</a>
    </div>
    <div>Test 1</div>
  </div>

  <div>
    <div class="scthd">
      <a class="op_cl">x</a>
    </div>
    <div>Test 2</div>
  </div>

  <div>
    <div class="scthd">
      <a class="op_cl">x</a>
    </div>
    <div>Test n</div>
  </div>
</div>
提前THX。

2 个答案:

答案 0 :(得分:0)

要了解您的问题,您需要首先了解在backbone.js中声明事件哈希时,这些事件将委派给视图的根el。在您的情况下发生的事情是,由于所有子视图都使用相同的#sections元素,因此它们的事件被绑定到同一元素。

我不确定为什么要将它们设置为相同的元素,因此根据您要执行的操作,您可以省略this.setElement($('#sections'));并让容器视图附加子视图或使用一些其他方法来附加子视图。至于将事件传递给容器视图,您可以在容器视图中声明事件。

答案 1 :(得分:0)

你设置你的观点的方式在概念上是错误的(至少在Backbone土地上),它会对这些结果产生影响。这里的主要错误是让所有子视图共享一个公共根元素。这是非常糟糕的一句话:

initialize: function() {
    this.setElement($('#sections'));
}

这在概念上是错误的,因为你以相反的方式分配责任。您可以将子视图附加到Sidebar,而不是拥有将根据所有需要的子视图构建自己的根Sidebar视图。

正如杰克在答案中正确说的那样,这也有关于事件处理的问题。当你说出类似的话时:

events: {
    'click a.op_cl': 'closeSection'
}

您将单击事件侦听器附加到视图的根元素,触发后,首先检查目标是否与选择器匹配,如果是,则执行回调。在这种情况下,您将10个事件侦听器附加到同一个元素(#section),当您单击某个链接时,每个元素都将匹配并触发。

您应该将子视图更改为

var SubView = Backbone.View.extend({

    tagName: 'li',

    template: _template('<div class="scthd"><a class="op_cl">x</a></div><div><%- content %></div>'),

    events: {
        'click a.op_cl': 'closeSection'
    },

    closeSection: function(event) {
        console.log('event was triggered');
    },

    render: function() {
        $(this.el).append(this.template({content:'Test ' + i});
        return this;
    }

});

然后将这些SubView个实例附加到Sidebar的{​​{1}}。