Backbone View: Inherit and extend events from parent

前端 未结 15 626
醉梦人生
醉梦人生 2020-11-30 16:50

Backbone\'s documentation states:

The events property may also be defined as a function that returns an events hash, to make it easier to programmatic

相关标签:
15条回答
  • 2020-11-30 17:15

    I've found a more interesting solutions in this article

    It use of the Backbone’s super and ECMAScript’s hasOwnProperty. The second of its progressives examples works like a charm. Here's a bit a code :

    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);
        },
        ...
    });
    

    You can also do that for ui and attributes.

    This example does not take care of the properties set by a function, but the author of the article offers a solution in that case.

    0 讨论(0)
  • 2020-11-30 17:15

    A pattern for this that I am fond of is modifying the constructor and adding some additional functionality:

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

    I prefer this method because you do not have to identify the parent -one less variable to change. I use the same logic for attributes and defaults.

    0 讨论(0)
  • 2020-11-30 17:18

    Wouldn't it be easier to create specialized base constructor from Backbone.View that handles the inheritance of events up the hierarchy.

    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
    }
    

    This allows us to reduce(merge) the events hash down the hierarchy whenever we create a new 'subclass'(child constructor) by using the redefined extend function.

    # 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: ....
    } 
    

    By creating a specialized view: BaseView that redefines the extend function, we can have subviews(like AppView, SectionView) that want to inherit their parent view's declared events simply do so by extending from BaseView or one of its derivatives.

    We avoid the need to programmatically define our event functions in our subviews, which in most cases need to refer to the parent constructor explicitly.

    0 讨论(0)
  • 2020-11-30 17:18

    If you are sure that the ParentView has the events defined as object and you don't need to define events dynamically in ChildView it is possible to simplify soldier.moth's answer further by getting rid of the function and using _.extend directly:

    var ParentView = Backbone.View.extend({
        events: {
            'click': 'onclick'
        }
    });
    
    var ChildView = ParentView.extend({
        events: _.extend({}, ParentView.prototype.events, {
            'click' : 'onclickChild'
        })
    });
    
    0 讨论(0)
  • 2020-11-30 17:21

    One way is:

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

    Another would be:

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

    To check whether Events is function or object

    var ChildView = ParentView.extend({
       events: function(){
          var parentEvents = ParentView.prototype.events;
          if(_.isFunction(parentEvents)){
              parentEvents = parentEvents();
          }
          return _.extend({},parentEvents,{
              'click' : 'onclickChild'
          });
       }
    });
    
    0 讨论(0)
  • 2020-11-30 17:28

    For Backbone version 1.2.3, __super__ works fine, and may even be chained. 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",
        }
        // ...
    });
    

    ... which - in A_View.js - will result in:

    events: {
        "click .a_foo": "a_bar",
        "click .b_foo": "b_bar",
        "click .c_foo": "c_bar",
    }
    
    0 讨论(0)
提交回复
热议问题