Представление магистрали: наследовать и расширять события от родителя



документация магистрали гласит:




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




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



Родительский Вид



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


Посмотреть Ребенка



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

15 ответов:

один из способов-это:

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'
   }
});

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

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

солдат.мотылек ответить на один хороший. Упрощая его дальше, вы можете просто сделать следующее

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

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

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

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

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

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

class ChildView extends ParentView
  events: ->
    _.extend {}, super,
      'bar' : 'doOtherThing'

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

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, который переопределяет функцию extend, мы можем иметь подвиды (например, AppView, SectionView), которые хотят чтобы наследовать объявленные события родительского представления, просто сделайте это, расширяясь от BaseView или одного из его производных.

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

короткая версия @soldier.последнее предложение мотылька:

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

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

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

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

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

к _super var, который доступен в любом coffeescript Class … extends …

// 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/

для магистральной версии 1.2.3, __super__ работает нормально, и может даже быть закован. Например:

// 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",
}

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

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

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 и атрибуты.

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

Это решение CoffeeScript работало для меня (и учитывает @soldier.предложение мотылька):

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

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

Если вы уверены, что ParentView имеет события, определенные как объект, и вам не нужно динамически определять события в ChildView можно упростить солдата.ответ мотылька далее, избавившись от функции и используя _.extend напрямую:

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

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

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

// App View
var AppView = Backbone.View.extend({

    constructor: function(){
        this.events = _.result(this, 'events', {});
        Backbone.View.apply(this, arguments);
    },

    _superEvents: function(events){
        var sooper = _.result(this.constructor.__super__, 'events', {});
        return _.extend({}, sooper, events);
    }

});

// Parent View
var ParentView = AppView.extend({

    events: {
        'click': 'onclick'
    }

});

// Child View
var ChildView = ParentView.extend({

    events: function(){
        return this._superEvents({
            'click' : 'onclickChild'
        });
    }

});

Я предпочитаю этот метод, потому что вам не нужно идентифицировать родительскую переменную, чтобы изменить ее. Я использую ту же логику для attributes и defaults.

Вау, здесь много ответов, но я думал, что предложу еще один. Если вы используете библиотеку BackSupport, она предлагает extend2. Если вы используете extend2 он автоматически заботится о слиянии events (а также defaults и аналогичные свойства) для вас.

вот небольшой пример:

var Parent = BackSupport.View.extend({
    events: {
        change: '_handleChange'
    }
});
var Child = parent.extend2({
    events: {
        click: '_handleClick'
    }
});
Child.prototype.events.change // exists
Child.prototype.events.click // exists

https://github.com/machineghost/BackSupport

чтобы сделать это полностью в родительском классе и поддерживать хэш событий на основе функции в дочернем классе, чтобы дети могли быть агностиками наследования (ребенок должен будет вызвать MyView.prototype.initialize если он переопределяет initialize):

var MyView = Backbone.View.extend({
  events: { /* ... */ },

  initialize: function(settings)
  {
    var origChildEvents = this.events;
    this.events = function() {
      var childEvents = origChildEvents;
      if(_.isFunction(childEvents))
         childEvents = childEvents.call(this);
      return _.extend({}, : MyView.prototype.events, childEvents);
    };
  }
});

Comments

    Ничего не найдено.