Событие нажатия кнопки Backbone.js запускается для всех экземпляров кнопки, а не только для того, который был нажат. Почему?

Я изучаю backbone.js и совсем новичок. У меня есть представление, которое действует как кнопка:

simpleButton = Backbone.View.extend({
     template: "<button class='${classes}'>${text}</button>",

     el: $("body"),

     events: {
         "click": "onClick",
         "focus": "onFocus",
         "blur": "onBlur"
     },

     initialize: function (args) {

         _.bindAll(this, 'render');
         this.rendered = false;
         this.text = args.text || 'button';
         this.classes = args.classes || [];
         this.classes.push('ui-button');
         //console.debug("Wh.views.simpleButton.initialize classes ",this.classes);
         if (args.autoRender === true) this.render();

     },

     render: function () {
         //console.debug("Wh.views.simpleButton.render classes ",this.classes);
         if (this.rendered === false) {
             $.tmpl(
                 this.template, {
                     classes: this.classes.join(' '),
                     text: this.text
                 }
             ).appendTo(this.el);
             this.rendered = true;
         }

     },

     //event handlers
     onClick: function (ev) {
         console.debug(this);
         alert("click on ", ev, this);
     },

     onFocus: function (ev) {
         ////console.debug(ev);
     },

     onBlur: function (ev) {

     }

 });

Моя проблема в том, что если я создаю две кнопки и нажимаю только одну из них, я получаю окно предупреждения два раза, а отладка, показывающая мне «это», сначала показывает первую кнопку, а затем вторую кнопку.

Я что-то пропустил?


person Vlad Nicula    schedule 23.08.2011    source источник
comment
см.: stackoverflow.com/questions/6402915/   -  person charlysisto    schedule 27.08.2011


Ответы (4)


События, которые вы определяете, привязаны к свойству "el" вашего представления. В вашем случае это «тело», поэтому, когда вы запускаете щелчок с двумя экземплярами представления simpleButton, у вас есть 2 из них, прослушивающих одно и то же событие.

Каждое представление, которое вы создаете, должно представлять один и только один элемент DOM, определенный свойством el. Итак, если вы хотите создать представление кнопки (не уверен, что это «лучшая практика» в реальной программе), вы можете:

SimpleButton =  Backbone.View.extend({
        template : "<button class='${classes}'>${text}</button>",

        tagName : "div", // defines the html tag that will wrap your template
        className: ".buttonbox", 
        ...
});

mybtn = new SimpleButton();
mybtn.render().appendTo('body')

Таким образом, ваше событие click будет касаться только одного div.buttonbox, внутри которого находится ваша кнопка.

Примечание. Основной идеей функции рендеринга является создание строки html, которую вы впоследствии будете использовать для добавления prepend или чего-то еще в DOM. Таким образом, если вы создаете много, вы можете сделать это, чтобы обновить DOM только один раз (обновление DOM дорого)...

person charlysisto    schedule 23.08.2011
comment
Спасибо, что разъяснили это. Теперь хорошо. Я решил добавить класс .inner в шаблон своих кнопок, и теперь я слушаю щелчок .inner, и он работает, он не срабатывает два раза! - person Vlad Nicula; 05.09.2011

Используйте это в своем представлении. Это отменит события щелчка.

initialize : function() {
    $(this.el).unbind("click");
}
person suresh    schedule 27.11.2012
comment
инициализировать: function() { $(this.el).unbind(click); } - person suresh; 27.11.2012
comment
хм... к чему комментарий? (непросвещенный я не вижу разницы :-) - вы в любой момент можете отредактировать свой пост и добавить уточнения. - person kleopatra; 27.11.2012
comment
Хорошее решение, хорошо работает при использовании Backbone js с PhoneGap, где каждое представление может иметь один и тот же элемент el DOM. - person Mina Wissa; 10.04.2013

Просто мысль о том, что создание Backbone.View для каждой кнопки в вашем приложении может привести к чрезмерной производительности, и вы не можете использовать функцию «делегата» в jQuery. Вместо этого я бы создал Backbone.View для родительского элемента этих кнопок.

Конечно, если у вас есть несколько специальных кнопок со сложной логикой, то они, вероятно, заслуживают своих собственных классов View. :)

person anh_ng8    schedule 03.11.2011
comment
У меня есть форма с большим количеством входных данных, и мне пришлось создать представление (и модель) для каждого, поскольку каждая модель соответствует вызову API. Думаете, это перебор? - person gerl; 28.01.2014
comment
@gerl: трудно количественно оценить множество входных данных. Однако, скажем, у вас есть 10-20 входных данных в форме, и вам нужно создать каждое представление для каждого из них, тогда да, это звучит как излишество. Что бы я сделал, так это рефакторинг модели, чтобы включить больше информации для заполнения большего количества входных данных, чтобы вы могли сократить количество представлений/моделей для этой формы. - person anh_ng8; 24.02.2014

Дайте вашим кнопкам уникальные идентификаторы, например <button id="button1"> и <button id="button2">, затем в хеше событий вам нужно указать событие нажатия и идентификатор кнопки, для которой вы хотите обработать это событие, например:

events : {
        "click #button1" : "onClick",
        "click #button2" : "doSomethingElse"
    }

Теперь это вызовет onClick() только тогда, когда вы нажмете кнопку с id=button1 и вызовите doSomethingElse(), когда вы нажмете кнопку с id=button2

person cjroebuck    schedule 24.08.2011
comment
Я хотел сделать столько кнопок, сколько захочу, поэтому решение #id мне не подходит. Однако вы правы, эта штука #id работает. Спасибо. - person Vlad Nicula; 05.09.2011
comment
вместо этого используйте класс и примените его ко всем вашим кнопкам <button class='clickable'>, тогда ваша запись о событии станет 'click .clickable' : 'onClick' надеюсь, что это поможет - person cjroebuck; 05.09.2011