백본보기 : 부모로부터 이벤트 상속 및 확장


115

Backbone의 문서는 다음과 같이 말합니다.

이벤트 속성은 이벤트 해시를 반환하는 함수로 정의되어 이벤트를 프로그래밍 방식으로 쉽게 정의하고 상위 뷰에서 상속 할 수 있습니다.

부모의보기 이벤트를 상속하고 확장하는 방법은 무엇입니까?

부모보기

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

어린이보기

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

답변:


189

한 가지 방법은 다음과 같습니다.

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

훌륭합니다 ... ChildView에서 상속하는 방법을 보여주기 위해 이것을 업데이트 할 수 있습니다 (프로토 타입 이벤트가 함수 또는 객체인지 확인) ... 아니면이 전체 상속 항목을 지나치게 생각하고있을 수도 있습니다.
brent

@brent 물론입니다. 세 번째 사례를 추가했습니다
soldier.moth

14
내가 착각하지 않았다면 parentEvents = _.result(ParentView.prototype, 'events');'수동으로' events함수 인지 확인 하는 대신 사용할 수 있어야 합니다.
Koen.

3
@Koen. _.result내가 전에 알아 차리지 못했던 밑줄 유틸리티 함수를 언급 한 +1 . 관심이있는 사람을 위해 다음은이 테마에 대한 다양한 변형이있는 jsfiddle입니다. jsfiddle
EleventyOne

1
여기에 2 센트를 투자하기 위해 두 번째 옵션이 최상의 솔루션이라고 생각합니다. 나는 이것이 진정으로 캡슐화 된 유일한 방법이라는 순수한 사실 때문에 이것을 말한다. 사용되는 유일한 컨텍스트는 this인스턴스 이름으로 부모 클래스를 호출하는 것과 비교하는 것입니다. 이것에 대해 대단히 감사합니다.
제시 제임스 잭슨 테일러

79

soldier.moth 대답은 좋은 것입니다. 더 단순화하면 다음을 수행 할 수 있습니다.

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

그런 다음 일반적인 방법으로 두 클래스에서 이벤트를 정의하십시오.


8
당신은 아마 스왑 원하는하지만 좋은 전화, this.eventsParentView.prototype.events모두 동일한 이벤트 핸들러를 정의 할 경우, 그렇지 않으면 부모의 핸들러는 자녀의 우선합니다.
soldier.moth

1
@ Soldier.moth, 알았어 내가 그것을 편집했습니다{},ParentView.prototype.events,this.events
AJP

1
분명히 이것은 작동하지만 내가 아는 것처럼 delegateEvents이벤트를 바인딩하기 위해 생성자에서 호출됩니다. 에서 확장 할 때 왜 initialize너무 늦지 않았습니까?
SelimOber

2
까다 롭지 만이 솔루션에 대한 내 문제는 다음과 같습니다. 다양하고 풍부한 뷰 계층 구조가있는 경우 필연적 initialize으로 몇 가지 경우 (그런 다음 해당 기능의 계층 관리도 처리해야 함)를 작성해야합니다. 이벤트 개체를 병합합니다. events병합 자체 를 유지하기 위해 나에게 더 깨끗한 것 같습니다 . 그 존재는 내가이 방법을 생각하지 않았을, 그것은 : 다른 방식으로 사물을보기로 강제하는 것이 좋다 말했다
EleventyOne

1
이 대답은 더 이상 유효하지 않습니다. delegateEvents가 초기화되기 전에 호출되기 때문입니다 (버전 1.2.3의 경우 해당됨). 주석이 추가 된 소스에서 쉽게 수행 할 수 있습니다.
Roey

12

또한이 defaults메서드를 사용 하여 빈 개체를 만들지 않을 수 있습니다 {}.

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

2
이로 인해 상위 핸들러가 하위 핸들러 뒤에 바인딩됩니다. 대부분의 경우 문제가되지 않지만 하위 이벤트가 상위 이벤트를 취소 (재정의하지 않음)해야하는 경우 불가능합니다.
Koen.

10

당신이 커피 스크립트를 사용하고 기능을 설정하면 events, 당신은 사용할 수 있습니다 super.

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

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

이것은 부모 이벤트 변수가 객체가 아닌 함수 인 경우에만 작동합니다.
Michael

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
}

이를 통해 재정의 된 확장 함수를 사용하여 새 '하위 클래스'(자식 생성자)를 만들 때마다 계층 구조 아래로 이벤트 해시를 줄이 (병합) 할 수 있습니다.

# 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

@ soldier.moth의 마지막 제안의 짧은 버전 :

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

2

이것은 또한 작동합니다.

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

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

스트레이트 super를 사용 하는 것은 나를 위해 작동하지 않았으며 수동으로 ParentView또는 상속 된 클래스를 지정했습니다 .

_super모든 coffeescript 내에서 사용할 수 있는 var 에 대한 액세스Class … extends …


2

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

Backbone 버전 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",
}

1

기사 에서 더 흥미로운 해결책을 찾았습니다.

백본의 사용 super 와 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속성에 .

이 예제는 함수에 의해 설정된 속성을 처리하지 않지만이 경우 기사 작성자가 솔루션을 제공합니다.


1

이 작업을 부모 클래스에서 전적으로 수행하고 자식 클래스에서 함수 기반 이벤트 해시를 지원하여 자식이 상속에 무관심 할 수 있도록하려면 (자식이 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);
    };
  }
});

0

이 CoffeeScript 솔루션은 저에게 효과적이었습니다 (@ soldier.moth의 제안을 고려함).

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

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

0

ParentView이벤트가 객체로 정의되어 있고 이벤트를 동적으로 정의 할 필요가없는 ChildView경우 함수를 제거하고 _.extend직접 사용하여 soldier.moth의 답변을 더 단순화 할 수 있습니다.

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

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

0

내가 좋아하는 패턴은 생성자를 수정하고 몇 가지 추가 기능을 추가하는 것입니다.

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


0

와, 여기에 많은 답변이 있지만 하나 더 제공 할 것이라고 생각했습니다. 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


3
나는 개념을 좋아하지만 원칙적으로 만 "extend2"가 적절한 함수 이름이라고 생각하는 모든 라이브러리를 전달합니다.
Yaniv에게

본질적으로 "Backbone.extend이지만 기능이 개선 된"함수의 이름에 대해 제안 할 수있는 모든 제안을 환영합니다. Extend 2.0 ( extend2)은 제가 생각해 낼 수있는 최고 였고, 그렇게 끔찍하다고 생각하지 않습니다. Backbone에 익숙한 사람은 이미를 사용하는 데 익숙해 extend져 있으므로 새로운 명령을 외울 필요가 없습니다.
machineghost

Github 저장소에 대한 문제를 열었습니다. :)
Yaniv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.