Backbone View: наследовать и расширять события от родителя - PullRequest
113 голосов
/ 23 февраля 2012

Документация Backbone гласит:

Свойство events также может быть определено как функция, которая возвращает хеш событий, чтобы упростить программное определение ваших событий, а также наследовать их от родительских представлений..

Как наследовать события представления родителя и расширять их?

Родительское представление

var ParentView = Backbone.View.extend({
   events: {
      'click': 'onclick'
   }
});

Дочернее представление

var ChildView = ParentView.extend({
   events: function(){
      ????
   }
});

Ответы [ 15 ]

187 голосов
/ 23 февраля 2012

Один способ:

var ChildView = ParentView.extend({
   events: function(){
      return _.extend({},ParentView.prototype.events,{
          'click' : 'onclickChild'
      });
   }
});

Другой способ:

var ParentView = Backbone.View.extend({
   originalEvents: {
      'click': 'onclick'
   },
   //Override this event hash in
   //a child view
   additionalEvents: {
   },
   events : function() {
      return _.extend({},this.originalEvents,this.additionalEvents);
   }
});

var ChildView = ParentView.extend({
   additionalEvents: {
      'click' : ' onclickChild'
   }
});

Чтобы проверить, является ли Event функцией или объектом

var ChildView = ParentView.extend({
   events: function(){
      var parentEvents = ParentView.prototype.events;
      if(_.isFunction(parentEvents)){
          parentEvents = parentEvents();
      }
      return _.extend({},parentEvents,{
          'click' : 'onclickChild'
      });
   }
});
79 голосов
/ 05 апреля 2012

Солдат.Молотый ответ хороший.Чтобы упростить его, вы можете просто сделать следующее

var ChildView = ParentView.extend({
   initialize: function(){
       _.extend(this.events, ParentView.prototype.events);
   }
});

Затем просто определите ваши события в любом классе обычным способом.

12 голосов
/ 27 октября 2012

Вы также можете использовать метод defaults, чтобы избежать создания пустого объекта {}.

var ChildView = ParentView.extend({
  events: function(){
    return _.defaults({
      'click' : 'onclickChild'
    }, ParentView.prototype.events);
  }
});
10 голосов
/ 23 августа 2013

Если вы используете CoffeeScript и установите функцию на events, вы можете использовать super.

class ParentView extends Backbone.View
  events: ->
    'foo' : 'doSomething'

class ChildView extends ParentView
  events: ->
    _.extend {}, super,
      'bar' : 'doOtherThing'
6 голосов
/ 26 мая 2015

Не было бы проще создать специализированный базовый конструктор из Backbone.View, который обрабатывает наследование событий в иерархии.

BaseView = Backbone.View.extend {
    # your prototype defaults
},
{
    # redefine the 'extend' function as decorated function of Backbone.View
    extend: (protoProps, staticProps) ->
      parent = this

      # we have access to the parent constructor as 'this' so we don't need
      # to mess around with the instance context when dealing with solutions
      # where the constructor has already been created - we won't need to
      # make calls with the likes of the following:   
      #    this.constructor.__super__.events
      inheritedEvents = _.extend {}, 
                        (parent.prototype.events ?= {}),
                        (protoProps.events ?= {})

      protoProps.events = inheritedEvents
      view = Backbone.View.extend.apply parent, arguments

      return view
}

Это позволяет нам уменьшать (объединять) хэш событий в иерархии всякий раз, когда мы создаем новый «подкласс» (дочерний конструктор) с помощью переопределенной функции расширения.

# AppView is a child constructor created by the redefined extend function
# found in BaseView.extend.
AppView = BaseView.extend {
    events: {
        'click #app-main': 'clickAppMain'
    }
}

# SectionView, in turn inherits from AppView, and will have a reduced/merged
# events hash. AppView.prototype.events = {'click #app-main': ...., 'click #section-main': ... }
SectionView = AppView.extend {
    events: {
        'click #section-main': 'clickSectionMain'
    }
}

# instantiated views still keep the prototype chain, nothing has changed
# sectionView instanceof SectionView => true 
# sectionView instanceof AppView => true
# sectionView instanceof BaseView => true
# sectionView instanceof Backbone.View => also true, redefining 'extend' does not break the prototype chain. 
sectionView = new SectionView { 
    el: ....
    model: ....
} 

Создавая специализированное представление: BaseView, которое переопределяет функцию расширения, мы можем иметь подпредставления (например, AppView, SectionView), которые хотят наследовать объявленные события своего родительского представления, просто делая это путем расширения из BaseView или одного из его производных.

Мы избегаем необходимости программно определять наши функции событий в наших подпредставлениях, которые в большинстве случаев должны явно ссылаться на родительский конструктор.

2 голосов
/ 21 апреля 2015

// ModalView.js
var ModalView = Backbone.View.extend({
	events: {
		'click .close-button': 'closeButtonClicked'
	},
	closeButtonClicked: function() { /* Whatever */ }
	// Other stuff that the modal does
});

ModalView.extend = function(child) {
	var view = Backbone.View.extend.apply(this, arguments);
	view.prototype.events = _.extend({}, this.prototype.events, child.events);
	return view;
};

// MessageModalView.js
var MessageModalView = ModalView.extend({
	events: {
		'click .share': 'shareButtonClicked'
	},
	shareButtonClicked: function() { /* Whatever */ }
});

// ChatModalView.js
var ChatModalView = ModalView.extend({
	events: {
		'click .send-button': 'sendButtonClicked'
	},
	sendButtonClicked: function() { /* Whatever */ }
});

http://danhough.com/blog/backbone-view-inheritance/

2 голосов
/ 17 августа 2014

Это также будет работать:

class ParentView extends Backbone.View
  events: ->
    'foo' : 'doSomething'

class ChildView extends ParentView
  events: ->
    _.extend({}, _.result(_super::, 'events') || {},
      'bar' : 'doOtherThing')

Использование прямого super не работало для меня, либо вручную указывало ParentView, либо унаследованный класс.

Доступ к _super var, доступному в любом коде кофе Class … extends …

2 голосов
/ 22 августа 2013

Краткая версия последнего предложения @ soldier.moth:

var ChildView = ParentView.extend({
  events: function(){
    return _.extend({}, _.result(ParentView.prototype, 'events') || {}, {
      'click' : 'onclickChild'
    });
  }
});
1 голос
/ 21 октября 2016

Я нашел более интересные решения в этой статье

Используется super Backbone и hasOwnProperty ECMAScript. Второй из его прогрессивных примеров работает как шарм. Вот немного кода:

var ModalView = Backbone.View.extend({
    constructor: function() {
        var prototype = this.constructor.prototype;

        this.events = {};
        this.defaultOptions = {};
        this.className = "";

        while (prototype) {
            if (prototype.hasOwnProperty("events")) {
                _.defaults(this.events, prototype.events);
            }
            if (prototype.hasOwnProperty("defaultOptions")) {
                _.defaults(this.defaultOptions, prototype.defaultOptions);
            }
            if (prototype.hasOwnProperty("className")) {
                this.className += " " + prototype.className;
            }
            prototype = prototype.constructor.__super__;
        }

        Backbone.View.apply(this, arguments);
    },
    ...
});

Вы также можете сделать это для атрибутов ui и .

В этом примере не рассматриваются свойства, установленные функцией, но автор статьи предлагает решение в этом случае.

1 голос
/ 12 января 2016

Для Backbone версии 1.2.3, __super__ работает нормально и может даже быть цепочкой. E.g.:

// A_View.js
var a_view = B_View.extend({
    // ...
    events: function(){
        return _.extend({}, a_view.__super__.events.call(this), { // Function - call it
            "click .a_foo": "a_bar",
        });
    }
    // ...
});

// B_View.js
var b_view = C_View.extend({
    // ...
    events: function(){
        return _.extend({}, b_view.__super__.events, { // Object refence
            "click .b_foo": "b_bar",
        });
    }
    // ...
});

// C_View.js
var c_view = Backbone.View.extend({
    // ...
    events: {
        "click .c_foo": "c_bar",
    }
    // ...
});

... который - в A_View.js - приведет к:

events: {
    "click .a_foo": "a_bar",
    "click .b_foo": "b_bar",
    "click .c_foo": "c_bar",
}
...