骨干视图:从父级继承和扩展事件

bre*_*ent 114 javascript backbone.js backbone-events

Backbone的文档说明:

events属性也可以定义为返回事件哈希的函数,以便以编程方式定义事件,并从父视图继承它们.

你如何继承父视图事件并扩展它们?

父视图

var ParentView = Backbone.View.extend({
   events: {
      'click': 'onclick'
   }
});
Run Code Online (Sandbox Code Playgroud)

儿童观

var ChildView = ParentView.extend({
   events: function(){
      ????
   }
});
Run Code Online (Sandbox Code Playgroud)

sol*_*oth 188

一种方法是:

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

另一个是:

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'
   }
});
Run Code Online (Sandbox Code Playgroud)

检查事件是函数还是对象

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

  • 如果我没有弄错你应该能够使用`parentEvents = _.result(ParentView.prototype,'events');`而不是'手动'检查`events`是否是一个函数. (14认同)
  • @Koen.+1提到下划线实用函数`_.result`,我以前没有注意到.对于任何有兴趣的人来说,这里有一个关于这个主题的一些变种:[jsfiddle](http://jsfiddle.net/QLd6E/) (3认同)

34m*_*4m0 79

士兵.这个答案很好.进一步简化它你可以做到以下几点

var ChildView = ParentView.extend({
   initialize: function(){
       _.extend(this.events, ParentView.prototype.events);
   }
});
Run Code Online (Sandbox Code Playgroud)

然后以典型的方式在任一类中定义您的事件.

  • 好的调用,虽然你可能想要交换`this.events`和`ParentView.prototype.events`,否则如果两个都在同一个事件上定义处理程序,那么Parent的处理程序将覆盖Child的. (7认同)
  • 这是非常挑剔的,但我对这个解决方案的问题是:如果你有一个多样化和丰富的视图层次结构,你将不可避免地发现自己在少数情况下编写`initialize`(然后不得不处理管理该函数的层次结构) )简单地合并事件对象.对我来说似乎更清洁,以保持`events`在其内部融合.话虽这么说,我不会想到这种方法,并且总是很高兴被迫以不同的方式看待事物:) (2认同)

jer*_*mel 12

您还可以使用该defaults方法来避免创建空对象{}.

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

  • 这会导致父处理程序在子处理程序之后绑定.在大多数情况下不是问题,但如果子事件应该取消(不覆盖)父事件,则不可能. (2认同)

Shu*_*awa 10

如果您使用CoffeeScript并将函数设置为events,则可以使用super.

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

class ChildView extends ParentView
  events: ->
    _.extend {}, super,
      'bar' : 'doOtherThing'
Run Code Online (Sandbox Code Playgroud)


Sha*_*w W 6

从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
}
Run Code Online (Sandbox Code Playgroud)

这允许我们在使用重新定义的扩展函数创建新的"子类"(子构造函数)时减少(合并)层次结构中的事件哈希.

# 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: ....
} 
Run Code Online (Sandbox Code Playgroud)

通过创建一个专门的视图:重新定义扩展函数的BaseView,我们可以通过从BaseView或其衍生物之一扩展来实现想要继承父视图声明事件的子视图(如AppView,SectionView).

我们避免在子视图中以编程方式定义事件函数的需要,在大多数情况下需要显式地引用父构造函数.