简体   繁体   English

多次触发主干 DOM 事件

[英]Backbone DOM events firing multiple times

I am building a backbone app for the first time - and it is going great.我是第一次构建主干应用程序 - 并且进展顺利。

However, I don't think I am creating views for my collection of models in the correct way and when I bind events they fire for every view when I only want them to fire for one.但是,我认为我没有以正确的方式为我的模型集合创建视图,并且当我绑定事件时,当我只希望它们为一个视图触发时,它们会为每个视图触发。

Here is my backbone code (a snippet):这是我的主干代码(片段):

        (function(){

        Series = Backbone.Model.extend({
            defaults:{
                active:false
            }
        });

        SeriesGridItemView = Backbone.View.extend({
            el:'#model-grid',
            defaults: {
                active : false
            },
            initialize: function(){
                this.render();
                this.listenTo(this.model, 'change', this.setState);
            },
            render: function(){
                this.template = _.template( $('#template-model-grid-item-view').html() );
                this.view = $(this.template(this.model.toJSON())).appendTo(this.$el);
            },
            setState: function(){
                this.active = this.model.get('active');
                this.view.toggleClass('active',this.active);
            },
            events: {
                'click':'toggle'
            },
            toggle: function(e){
                e.stopPropagation();
                e.preventDefault();
                console.log('clicked');
                return false;
            }

        });

        SeriesCollection = Backbone.Collection.extend({
            model: Series,
            setPrice : function(p){
                this.forEach(function(m){
                    var active = 0;
                    _.each(m.get('vehicles'),function(v){
                        if(v.price <=p){
                            v.active = true;
                            active++;
                        }
                        else{
                            v.active = false;
                        }
                    });
                    m.set('active',active>0);
                });
            }
        });

        series = new SeriesCollection(window.BMW.data.series);
        series.forEach(function(m,i){
            var c = i+1;
            if(c > 3){
                c%=3;
            }
            m.set('column','1');
            new SeriesGridItemView({model:m});
        });
    })();

And here is the JSON that constructs the models:这是构建模型的 JSON:

window.BMW.data.series = [
    {
        seriesId:1,
        name:'1 Series',
        slug:'1-series',
        order:0,
        vehicles:[
            {
                seriesId:1,
                price:200
            },
            {
                seriesId:2,
                price:300
            }
        ]
    },
    {
        seriesId:2,
        name:'3 Series',
        slug:'3-series',
        order:1,
        vehicles:[
            {
                seriesId:1,
                price:400
            },
            {
                seriesId:2,
                price:500
            }
        ]
    },
    {
        seriesId:3,
        name:'4 Series',
        slug:'4-series',
        order:3,
        vehicles:[
            {
                seriesId:1,
                price:100
            },
            {
                seriesId:2,
                price:300
            }
        ]
    },
    {
        seriesId:4,
        name:'6 Series',
        slug:'6-series',
        order:4,
        vehicles:[
            {
                seriesId:1,
                price:100
            },
            {
                seriesId:2,
                price:300
            }
        ]
    },
    {
        seriesId:6,
        name:'X3',
        slug:'x3',
        order:5,
        vehicles:[
            {
                seriesId:1,
                price:500
            },
            {
                seriesId:2,
                price:800
            }
        ]
    }
];

And here is my template for the views这是我的视图模板

<script type="text/template" id="template-model-grid-item-view">
    <div id="series-<%=seriesId%>" class="grid-item-view column-<%=column%>">
        <div class="label"><%= name %></div>
        <div class="thumbnail">
            <img src="/Content/themes/BMW/img/series/small/<%= slug %>.png"/>
        </div>
    </div>
</script>

The views assemble correctly, but when I click one view, the event fires on all of the views.视图正确组装,但是当我单击一个视图时,事件会在所有视图上触发。 Can someone please point me in the right direction?有人可以指出我正确的方向吗?

Since you omitted the selector in your events object of your views the following applies由于您在视图的events对象中省略了选择器,因此以下适用

Per the Backbone Documentation : Omitting the selector causes the event to be bound to the view's root element (this.el).根据 Backbone文档Omitting the selector causes the event to be bound to the view's root element (this.el).

The problem is each of the SeriesGridItemView 's bind click events to #model-grid and each view is a child of #model-grid .问题是每个SeriesGridItemView的绑定click事件到#model-grid并且每个视图都是#model-grid的子视图。 In your example, you register 5 click events and when you click on any of your views, all 5 events are triggered.在您的示例中,您注册了 5 个点击事件,当您点击任何视图时,所有 5 个事件都会被触发。

Without changing any of your other code, one solution is to setup you events object to return a function so you can specify an id selector for each of your views.在不更改任何其他代码的情况下,一种解决方案是设置您的events对象以返回一个函数,以便您可以为每个视图指定一个id选择器。

events: function() {
  var selector = '#series-' + this.model.get('seriesId'); // this id corresponds to your template id
  var ev = {};
  ev['click ' + selector] = 'toggle';
  return ev;
},

Another option and the one I prefer, is to not specify #model-grid as your root element for all your views.我更喜欢的另一种选择是不将#model-grid指定为所有视图的根元素。 It would end up looking like: demo它最终看起来像:演示

SeriesGridItemView = Backbone.View.extend({
  // remove the following line
  el:'#model-grid', 

  // .. all else is the same ../
});

series = new SeriesCollection(window.BMW.data.series);
  series.forEach(function(m,i){
    var c = i+1;
    if(c > 3){
      c%=3;
    }
    m.set('column','1');
    $('#model-grid').append(new SeriesGridItemView({model:m}).el);
});

A side suggetion侧面建议

  1. In your render function, there's no need to create variable, you can access your element by using $ :在您的render函数中,无需创建变量,您可以使用$访问您的元素:

     render: function(){ this.template = _.template( $('#template-model-grid-item-view').html() ); this.$el.append(this.template(this.model.toJSON()))); }, setState: function(){ this.active = this.model.get('active'); this.$el.toggleClass('active',this.active); },

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM