बैकबोन व्यू: इनहेरिट करें और माता-पिता से घटनाओं का विस्तार करें


115

बैकबोन के प्रलेखन में कहा गया है:

ईवेंट प्रॉपर्टी को एक फ़ंक्शन के रूप में भी परिभाषित किया जा सकता है जो एक ईवेंट को लौटाता है, जिससे आपकी ईवेंट को प्रोग्रामेटिक रूप से परिभाषित करना आसान हो जाता है, साथ ही साथ उन्हें माता-पिता के विचारों से विरासत में मिला है।

आप माता-पिता की घटनाओं को कैसे देखते हैं और उनका विस्तार करते हैं?

जनक दृश्य

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

यह बहुत अच्छा है ... हो सकता है कि आप इसे यह दिखाने के लिए अपडेट कर सकें कि आप चाइल्ड व्यू से कैसे इनहेरिट करेंगे (यह देखें कि क्या प्रोटोटाइप ईवेंट एक फंक्शन या ऑब्जेक्ट है) ... या हो सकता है कि मैं इस पूरे इनहेरिटेंस सामान को खत्म कर रहा हूं।
ब्रेंट

@ एसब्रेंट ज़रूर, सिर्फ तीसरा मामला
सैनिक

14
यदि मैं गलत नहीं हूँ, तो आपको parentEvents = _.result(ParentView.prototype, 'events');'मैन्युअल' जाँच के बजाय उपयोग करना चाहिए, अगर eventsयह एक फ़ंक्शन है।
कोएन।

3
@Koen। अंडरस्कोर उपयोगिता फ़ंक्शन का उल्लेख करने के लिए +1 _.result, जिसे मैंने पहले नहीं देखा था। किसी की दिलचस्पी के लिए, यहाँ इस विषय पर विविधताओं का एक समूह के साथ एक jsfiddle है
EleventyOne

1
बस अपने दो सेंट को यहां फेंकने के लिए, मेरा मानना ​​है कि दूसरा विकल्प सबसे अच्छा समाधान है। मैं यह सरासर तथ्य के कारण कहता हूं कि यह एकमात्र तरीका है जो वास्तव में अतिक्रमित है। thisउदाहरण के नाम से मूल वर्ग को कॉल करने के लिए उपयोग किया जाने वाला एकमात्र संदर्भ बनाम है। इसके लिए आपको बहुत धन्यवाद।
जेसी जैम्स जैकसन टेलर

79

सैनिक। पोथ का उत्तर एक अच्छा है। इसे और सरल बनाते हुए आप केवल निम्नलिखित कार्य कर सकते हैं

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

फिर बस अपने घटनाओं को विशिष्ट तरीके से कक्षा में परिभाषित करें।


8
अच्छी कॉल, हालांकि आप शायद स्वैप करना चाहते हैं this.eventsऔर ParentView.prototype.eventsअन्यथा यदि दोनों एक ही घटना पर हैंडलर को परिभाषित करते हैं तो पेरेंट हैंडलर चाइल्ड्स को ओवरराइड कर देगा।
सैनिक ०५

1
@ Sold.m.moth, ठीक है, मैंने इसे संपादित करने के लिए{},ParentView.prototype.events,this.events
AJP

1
स्पष्ट रूप से यह काम करता है, लेकिन जैसा कि मुझे पता है, delegateEventsघटनाओं को बांधने के लिए निर्माता में कहा जाता है। तो जब आप इसे बढ़ाते हैं initialize, तो कैसे आते हैं कि बहुत देर नहीं हुई है?
सेलिमोबर

2
यह नाइट-पिकी है, लेकिन इस समाधान के साथ मेरा मुद्दा है: यदि आपके पास विचारों की विविधता और भरपूर मात्रा में पदानुक्रम है, तो आप अनिवार्य रूप से initializeकुछ मामलों में खुद को लिख पाएंगे (फिर उस फ़ंक्शन के पदानुक्रम को प्रबंधित करने के लिए भी) इवेंट ऑब्जेक्ट मर्ज करें। मेरे eventsभीतर विलय रखने के लिए मुझे क्लीनर लगता है। कहा जा रहा है, मैंने इस दृष्टिकोण के बारे में नहीं सोचा होगा, और हमेशा चीजों को एक अलग तरीके से देखने के लिए मजबूर होना अच्छा लगता है :)
EleventyOne

1
यह उत्तर अधिक मान्य नहीं है क्योंकि डेलिगेट ईवेंट्स को इनिशियलाइज़ करने से पहले कहा जाता है (यह संस्करण 1.2.3 के लिए सच है) - एनोटेट स्रोत में इसके लिए आसान है।
13

12

आप defaultsखाली वस्तु बनाने से बचने के लिए भी विधि का उपयोग कर सकते हैं {}

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

2
यह माता-पिता के संचालकों को बाल संचालकों के बाद बाध्य करने का कारण बनता है। ज्यादातर मामलों में कोई समस्या नहीं है, लेकिन अगर किसी बच्चे की घटना को रद्द करना चाहिए (ओवरराइड नहीं) तो माता-पिता की घटना संभव नहीं है।
कोएन।

10

यदि आप CoffeeScript का उपयोग करते हैं और एक फ़ंक्शन सेट करते हैं events, तो आप उपयोग कर सकते हैं super

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

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

यह केवल तभी काम करता है जब पैरेंट इवेंट्स चर एक वस्तु के बजाय एक फ़ंक्शन है।
माइकल

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

एक विशेष दृश्य बनाकर: बेस व्यू जो फ़ंक्शन को पुनर्परिभाषित करता है, हमारे पास सबव्यू (जैसे ऐपव्यू, सेक्शन व्यू) हो सकते हैं जो अपने माता-पिता की घोषित घटनाओं को विरासत में प्राप्त करना चाहते हैं, बस बेस व्यू या इसके डेरिवेटिव में से एक का विस्तार करके ऐसा करते हैं।

हम अपने उप-साक्षात्कारों में अपने ईवेंट फ़ंक्शंस को प्रोग्रामेटिक रूप से परिभाषित करने की आवश्यकता से बचते हैं, जो कि ज्यादातर मामलों में स्पष्ट रूप से पैरेंट कंस्ट्रक्टर को संदर्भित करने की आवश्यकता होती है।


2

लघु संस्करण @ सैनिक। पोथ का अंतिम सुझाव:

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संस्करण तक पहुंच जो किसी भी कॉफ़ीस्क्रिप्ट में उपलब्ध है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

बैकबोन संस्करण 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

मुझे इसमें एक और दिलचस्प समाधान मिला है लेख

यह बैकबोन के सुपर और 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 समाधान ने मेरे लिए काम किया (और खाते में @ सैनिक का सुझाव है):

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

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

0

यदि आप सुनिश्चित हैं कि ParentViewघटनाओं को ऑब्जेक्ट के रूप में परिभाषित किया गया है और आपको ChildViewफ़ंक्शन को गतिशील रूप से परिभाषित करने की आवश्यकता नहीं है , तो फ़ंक्शन से छुटकारा पाने और _.extendसीधे उपयोग करके सैनिकपॉथ के उत्तर को और सरल करना संभव है :

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
मुझे अवधारणा पसंद है, लेकिन, सिद्धांत रूप में, मैं किसी भी पुस्तकालय पर गुजरता हूं जो सोचता है कि "विस्तार 2" एक उचित फ़ंक्शन नाम है।
यानिव

मैं किसी भी सुझाव का स्वागत करूंगा जो आप एक फ़ंक्शन का नाम दे सकते हैं जो अनिवार्य रूप से "Backbone.extend, लेकिन बेहतर कार्यक्षमता के साथ" है। एक्सटेंड 2.0 ( extend2) सबसे अच्छा था जो मैं साथ आ सकता था, और मुझे नहीं लगता कि यह सब भयानक है: बैकबोन के लिए इस्तेमाल किया जाने वाला कोई भी पहले से ही उपयोग किया जाता है extend, इसलिए इस तरह से उन्हें एक नई कमांड को याद करने की आवश्यकता नहीं है।
मशीनगॉस्ट

इसके बारे में गितुब रेपो पर एक मुद्दा खोला। :)
यानिव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.